home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / fslcl / fslclLookup.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-27  |  78.7 KB  |  2,441 lines

  1. /* 
  2.  * fslclLookup.c --
  3.  *
  4.  *    The routines in the module manage the directory structure.
  5.  *    The top level loop is in FslclLookup, and it is the workhorse
  6.  *    of the Local Domain that is called by procedures like FslclOpen.
  7.  *    Files and directories are also created, deleted, and renamed
  8.  *    directly (or indirectly) through FslclLookup.
  9.  *
  10.  *    Support for heterogenous systems is done here by expanding "$MACHINE"
  11.  *    in pathnames to a string like "sun3" or "spur".
  12.  *
  13.  * Copyright 1987 Regents of the University of California
  14.  * All rights reserved.
  15.  * Permission to use, copy, modify, and distribute this
  16.  * software and its documentation for any purpose and without
  17.  * fee is hereby granted, provided that the above copyright
  18.  * notice appear in all copies.  The University of California
  19.  * makes no representations about the suitability of this
  20.  * software for any purpose.  It is provided "as is" without
  21.  * express or implied warranty.
  22.  */
  23.  
  24. #ifndef lint
  25. static char rcsid[] = "$Header: /sprite/src/kernel/fslcl/RCS/fslclLookup.c,v 9.21 91/07/26 17:15:37 mendel Exp $ SPRITE (Berkeley)";
  26. #endif not lint
  27.  
  28.  
  29. #include <sprite.h>
  30. #include <fs.h>
  31. #include <fsconsist.h>
  32. #include <fsutil.h>
  33. #include <fsNameOps.h>
  34. #include <fsprefix.h>
  35. #include <fsdm.h>
  36. #include <fslclInt.h>
  37. #include <fslcl.h>
  38. #include <fslclNameHash.h>
  39. #include <fscache.h>
  40. #include <fsutilTrace.h>
  41. #include <fsStat.h>
  42. #include <rpc.h>
  43. #include <net.h>
  44. #include <vm.h>
  45. #include <string.h>
  46. #include <proc.h>
  47. #include <dbg.h>
  48. #ifdef SOSP91
  49. #include  <sospRecord.h>
  50. #include <timer.h>
  51. #endif
  52.  
  53. /*
  54.  * Debugging flags.
  55.  */
  56. int fslclComponentTrace = FALSE;
  57. extern int fsprefix_FileNameTrace;
  58.  
  59. int fsCompacts;        /* The number of times a directory block was so
  60.              * fragmented that we could have compacted it to
  61.              * make room for a new entry in the directory */
  62. /*
  63.  * A cache of recently seen pathname components is kept in a hash table.
  64.  * The hash table gets initialized in Fsdm_AttachDisk after the first disk
  65.  * gets attached.
  66.  * The name caching can be disabled by setting the fslclNameCaching flag to FALSE.
  67.  */
  68.  
  69. FslclHashTable fslclNameTable;
  70. FslclHashTable *fslclNameTablePtr = (FslclHashTable *)NIL;
  71. Boolean fslclNameCaching = TRUE;
  72. int fslclNameHashSize = FSLCL_NAME_HASH_SIZE;
  73.  
  74. /*
  75.  * Forward Declarations.
  76.  */
  77.  
  78. static ReturnStatus FindComponent _ARGS_((Fsio_FileIOHandle *parentHandlePtr, 
  79.         char *component, int compLen, Boolean isDotDot, 
  80.         Fsio_FileIOHandle **curHandlePtrPtr, int *dirOffsetPtr));
  81. static ReturnStatus InsertComponent _ARGS_((Fsio_FileIOHandle *curHandlePtr, 
  82.         char *component, int compLen, int fileNumber,
  83.         int *dirOffsetPtr));
  84. static ReturnStatus DeleteComponent _ARGS_((Fsio_FileIOHandle *parentHandlePtr,
  85.         char *component, int compLen, int *dirOffsetPtr));
  86. static ReturnStatus ExpandLink _ARGS_((Fsio_FileIOHandle *curHandlePtr, 
  87.         char *curCharPtr, int offset, char nameBuffer[]));
  88. static ReturnStatus GetHandle _ARGS_((int fileNumber, 
  89.         Fsdm_FileDescriptor *newDescPtr, 
  90.         Fsio_FileIOHandle *curHandlePtr, char *name, 
  91.         Fsio_FileIOHandle **newHandlePtrPtr));
  92. static ReturnStatus CreateFile _ARGS_((Fsdm_Domain *domainPtr, 
  93.         Fsio_FileIOHandle *parentHandlePtr, char *component, 
  94.         int compLen, int fileNumber, int type, int permissions, 
  95.         Fs_UserIDs *idPtr, Fsio_FileIOHandle **curHandlePtrPtr, 
  96.         int *dirOffsetPtr));
  97. static ReturnStatus WriteNewDirectory _ARGS_((Fsio_FileIOHandle *curHandlePtr,
  98.         Fsio_FileIOHandle *parentHandlePtr));
  99. static ReturnStatus LinkFile _ARGS_((Fsio_FileIOHandle *parentHandlePtr,
  100.         char *component, int compLen, int fileNumber, int logOp, 
  101.         Fsio_FileIOHandle **curHandlePtrPtr));
  102. static ReturnStatus OkToMoveDirectory _ARGS_((
  103.         Fsio_FileIOHandle *newParentHandlePtr, 
  104.         Fsio_FileIOHandle *curHandlePtr));
  105. static ReturnStatus MoveDirectory _ARGS_((Time *modTimePtr, 
  106.         Fsio_FileIOHandle *newParentHandlePtr, 
  107.         Fsio_FileIOHandle *curHandlePtr));
  108. static ReturnStatus GetParentNumber _ARGS_((Fsio_FileIOHandle *curHandlePtr,
  109.         int *parentNumberPtr));
  110. static ReturnStatus SetParentNumber _ARGS_((Fsio_FileIOHandle *curHandlePtr, 
  111.         int newParentNumber));
  112. static ReturnStatus DeleteFileName _ARGS_((Fsio_FileIOHandle *parentHandlePtr,
  113.         Fsio_FileIOHandle *curHandlePtr, char *component, 
  114.         int compLen, int forRename, Fs_UserIDs *idPtr, int logOp));
  115. static void    CloseDeletedFile _ARGS_((Fsio_FileIOHandle **parentHandlePtrPtr,
  116.                     Fsio_FileIOHandle **curHandlePtrPtr));
  117. static Boolean DirectoryEmpty _ARGS_((Fsio_FileIOHandle *handlePtr));
  118. static ReturnStatus CheckPermissions _ARGS_((Fsio_FileIOHandle *handlePtr, 
  119.         int useFlags, Fs_UserIDs *idPtr, int type));
  120. static ReturnStatus CacheDirBlockWrite _ARGS_((Fsio_FileIOHandle *handlePtr, 
  121.         Fscache_Block *blockPtr, int blockNum, int length));
  122.  
  123.  
  124. /*
  125.  *----------------------------------------------------------------------
  126.  *
  127.  * FslclLookup --
  128.  *
  129.  *    The guts of local file name lookup.  This does a recursive
  130.  *    directory lookup of a file pathname.  The success of the lookup
  131.  *    depends on useFlags and the type.  The process needs to
  132.  *    have read permission along the path, and other permissions on
  133.  *    the target file itself according to useFlags. The type of the
  134.  *    target file has to agree with the type parameter.
  135.  *
  136.  *    The major and minor fields of the Fs_FileID for local files correspond
  137.  *    to the domain and fileNumber, respectively, of a file.  The domain
  138.  *    is an index into the set of active domains (disks), and the fileNumber
  139.  *    is an index into the array of file descriptors on disk.
  140.  *
  141.  * Results:
  142.  *    If SUCCESS is returned then *handlePtrPtr contains a valid file
  143.  *    handle.  This handle should be released with FsLocalClose.
  144.  *    If FS_LOOKUP_REDIRECT is returned then **newNameInfoPtrPtr contains
  145.  *    the new file name that the client takes back to its prefix table.
  146.  *
  147.  * Side effects:
  148.  *    After a successful lookup the returned handle is locked and has
  149.  *    another reference to it.  Also, the domain in which the file was
  150.  *    found has an extra reference that needs to be released with
  151.  *    Fsdm_DomainRelease as soon as our caller is finished with the handle.
  152.  *
  153.  *----------------------------------------------------------------------
  154.  */
  155. #ifdef SOSP91
  156. Timer_Ticks totalNameTime = {0};
  157. Fs_FileID NullFileID = {0};
  158. #endif
  159. ReturnStatus
  160. FslclLookup(prefixHdrPtr, relativeName, rootIDPtr, useFlags, type, clientID,
  161.         idPtr, permissions, fileNumber, handlePtrPtr, newNameInfoPtrPtr)
  162.     Fs_HandleHeader *prefixHdrPtr;    /* Handle from the prefix table or
  163.                      * the current working directory */
  164.     char *relativeName;            /* Name to lookup relative to the
  165.                      * file indicated by prefixHandlePtr */
  166.     Fs_FileID *rootIDPtr;        /* File ID of the root of the domain */
  167.     int useFlags;            /* FS_READ|FS_WRITE|FS_EXECUTE,
  168.                      * FS_CREATE|FS_EXCLUSIVE, FS_OWNER,
  169.                      * FS_LINK, FS_FOLLOW (links) */
  170.     int type;                /* File type which to succeed on.  If
  171.                      * this is FS_FILE, then any type will
  172.                      * work. */
  173.     int clientID;            /* Host ID of the client doing the open.
  174.                      * Require to properly expand $MACHINE
  175.                      * in pathnames */
  176.     Fs_UserIDs *idPtr;            /* User and group IDs */
  177.     int permissions;            /* Permission bits to use on a newly
  178.                      * created file. */
  179.     int fileNumber;            /* File number to link to if FS_LINK
  180.                      * useFlag is present */
  181.     Fsio_FileIOHandle **handlePtrPtr;    /* Result, the handle for the file.
  182.                      * This is returned locked.  Also,
  183.                      * its domain has a reference which
  184.                      * needs to be released. */
  185.     Fs_RedirectInfo **newNameInfoPtrPtr;    /* Redirect Result, the pathname left
  186.                      * after it leaves our domain */
  187. {
  188.     register char     *curCharPtr;    /* Pointer into the path name */
  189.     Fsio_FileIOHandle *parentHandlePtr; /* Handle for parent dir. */
  190.     register char    *compPtr;    /* Pointer into component. */
  191.     register ReturnStatus status = SUCCESS;
  192.     register int     compLen = 0;    /* The length of component */
  193.     Fsio_FileIOHandle    *curHandlePtr;    /* Handle for the current spot in
  194.                      * the directory structure */
  195.     Fsdm_Domain *domainPtr;        /* Domain of the lookup */
  196.     char component[FS_MAX_NAME_LENGTH]; /* One component of the path name */
  197.     char *newNameBuffer;        /* Extra buffer used after a symbolic
  198.                      * link has been expanded */
  199.     int numLinks = 0;            /* The number of links that have been
  200.                      * expanded. Used to check against
  201.                      * loops. */
  202.     int    logOp;                /* Dir log operation. */
  203.     int dirFileNumber;            /* File number od directory being 
  204.                      * operated on. */
  205.     int    dirOffset;            /* Offset of directory entry in the
  206.                      * directory being operated on. */
  207.     ClientData    logClientData;        /* Client data for directory change
  208.                      * logging. */
  209. #ifdef SOSP91
  210. #define MAX_RECORDS 20
  211.     char buf[SOSP_LOOKUP_OFFSET+MAX_RECORDS*sizeof(Fs_FileID)];
  212.     Fs_FileID *sospTracePtr = (Fs_FileID*)(buf+SOSP_LOOKUP_OFFSET);
  213.     Timer_Ticks startTicks, endTicks;
  214.     int sospTraceCount = 0;
  215.     Timer_GetCurrentTicks(&startTicks);
  216.     bcopy((Address)prefixHdrPtr, (Address)sospTracePtr,
  217.         sizeof(Fs_FileID));
  218.     sospTracePtr++;
  219.     sospTraceCount++;
  220. #endif
  221.  
  222.     /*
  223.      * Get a handle on the domain of the file.  This is needed for disk I/O.
  224.      * Remember that the <major> field of the fileID is a domain number.
  225.      */
  226.     domainPtr = Fsdm_DomainFetch(prefixHdrPtr->fileID.major, FALSE);
  227.     if (domainPtr == (Fsdm_Domain *)NIL) {
  228.     return(FS_DOMAIN_UNAVAILABLE);
  229.     }
  230.  
  231.     if (prefixHdrPtr->fileID.type != FSIO_LCL_FILE_STREAM) {
  232.     printf("FslclLookup, bad prefix handle type <%d> for {%s}%s\n",
  233.         prefixHdrPtr->fileID.type,
  234.         Fsutil_HandleName(prefixHdrPtr), relativeName);
  235.     return(FS_DOMAIN_UNAVAILABLE);
  236.     }
  237. #ifdef SOSP91
  238.     SOSP_IN_NAME_LOOKUP_FIELD = 1;
  239. #endif
  240.     /*
  241.      * Duplicate the prefixHandle into the handle for the current point
  242.      * in the directory.  This locks and ups the reference count on the handle.
  243.      */
  244.     curCharPtr = relativeName;
  245.     curHandlePtr = Fsutil_HandleDupType(Fsio_FileIOHandle, prefixHdrPtr);
  246.     parentHandlePtr = (Fsio_FileIOHandle *)NIL;
  247.     newNameBuffer = (char *)NIL;
  248.     /*
  249.      * Loop through the pathname expanding links and checking permissions.
  250.      * Creations and deletions are handled after this loop.
  251.      */
  252.     fs_Stats.lookup.number++;
  253.     while (*curCharPtr != '\0' && status == SUCCESS) {
  254.     status = CheckPermissions(curHandlePtr, FS_READ, idPtr, FS_DIRECTORY);
  255.     if (status != SUCCESS) {
  256.         break;
  257.     }
  258.     /*
  259.      * Get the next component.  We make a special check here
  260.      * for "$MACHINE" embedded in the pathname.  This gets expanded
  261.      * to a machine type string, i.e. "sun3" or "spur", sort of like
  262.      * a symbolic link.  The value is dependent on the ID of the client
  263.      * doing the open.  For the local host we use a compiled in string so
  264.      * we can bootstrap ok, and for other clients we get the machine
  265.      * type string from the net module.  (why net?  why not...
  266.      * Net_InstallRoute installs a host's name and machine type.)
  267.      */
  268. #define SPECIAL        "$MACHINE"
  269. #define SPECIAL_LEN    8
  270.     compPtr = component;
  271.     while (*curCharPtr != '/' && *curCharPtr != '\0') {
  272.         if (*curCharPtr == '$' &&
  273.         (strncmp(curCharPtr, SPECIAL, SPECIAL_LEN) == 0)) {
  274.         char machTypeBuffer[32];
  275.         char *machType;
  276.  
  277.         if (fslclComponentTrace) {
  278.             printf(" $MACHINE -> ");
  279.         }
  280.         fs_Stats.lookup.numSpecial++;
  281.         if (clientID == rpc_SpriteID) {
  282.             /*
  283.              * Can't count on the net stuff being setup for ourselves
  284.              * as that is done via a user program way after bootting.
  285.              * Instead, use a compiled in string.  This is important
  286.              * when opening "/initSprite", which is a link to 
  287.              * "/initSprite.$MACHINE", when running on the root server.
  288.              */
  289.             machType = mach_MachineType;
  290.         } else {
  291.             Net_SpriteIDToMachType(clientID, 32, machTypeBuffer);
  292.             if (*machTypeBuffer == '\0') {
  293.             printf(
  294.              "FslclLookup, no machine type for client %d\n",
  295.                 clientID);
  296.             machType = "unknown";
  297.             } else {
  298.             machType = machTypeBuffer;
  299.             }
  300.         }
  301.         while (*machType != '\0') {
  302.             *compPtr++ = *machType++;
  303.             if (compPtr - component >= FS_MAX_NAME_LENGTH) {
  304.             status = FS_FILE_NOT_FOUND;
  305.             goto endScan;
  306.             }
  307.         }
  308.         curCharPtr += SPECIAL_LEN;
  309. #undef SPECIAL
  310. #undef SPECIAL_LEN
  311.         } else {
  312.         *compPtr++ = *curCharPtr++;
  313.         }
  314.         if (compPtr - component >= FS_MAX_NAME_LENGTH) {
  315.         status = FS_FILE_NOT_FOUND;
  316.         goto endScan;
  317.         }
  318.     }
  319.     fs_Stats.lookup.numComponents++;
  320.     *compPtr = '\0';
  321.     compLen = compPtr - component;
  322.     if (fslclComponentTrace) {
  323.         printf(" %s ", component);
  324.     }
  325.     /*
  326.      * Skip intermediate and trailing slashes so that *curCharPtr
  327.      * is Null when 'component' has the last component of the name.
  328.      */
  329.     while (*curCharPtr == '/') {
  330.         curCharPtr++;
  331.     }
  332.     /*
  333.      * There are three cases for what the next component is:
  334.      * a sub-directory (or file), dot, and dot-dot.
  335.      */
  336.     if ((compLen == 2) && component[0] == '.' && component[1] == '.') {
  337.         /* 
  338.          * Going to the parent directory ".."
  339.          */
  340.         if (curHandlePtr->hdr.fileID.minor == rootIDPtr->minor) {
  341.         /*
  342.          * We are falling off the top of the domain.  Make the
  343.          * remaining part of the filename, including "../",
  344.          * available to our caller so it can go back to the prefix
  345.          * table.  Setting the prefixLength to zero indicates
  346.          * there is no prefix information in this LOOKUP_REDIRECT
  347.          */
  348.         *newNameInfoPtrPtr = mnew(Fs_RedirectInfo);
  349.         (*newNameInfoPtrPtr)->prefixLength = 0;
  350.         (void)strcpy((*newNameInfoPtrPtr)->fileName, "../");
  351.         (void)strcat((*newNameInfoPtrPtr)->fileName, curCharPtr);
  352.         fs_Stats.lookup.parent++;
  353.         status = FS_LOOKUP_REDIRECT;
  354.         } else {
  355.         /*
  356.          * Advance curHandlePtr to the parent, "..".
  357.          * FindComponent will unlock its parentHandlePtr (the directory
  358.          * containing "..") after scanning it but before grabbing
  359.          * the handle for "..".  This prevents deadlock with another
  360.          * process descending the other way along the path.  
  361.          * We then nuke our own "parent" because it really isn't a
  362.          * parent anymore.
  363.          */
  364.         if (parentHandlePtr != (Fsio_FileIOHandle *)NIL) {
  365.             Fsutil_HandleRelease(parentHandlePtr, TRUE);
  366.         }
  367.         parentHandlePtr = curHandlePtr;
  368.         status = FindComponent(parentHandlePtr, component, compLen,
  369.                 TRUE, &curHandlePtr, &dirOffset);
  370.         /*
  371.          * Release the handle while being careful about its lock.
  372.          * The parent handle is normally aready unlocked by
  373.          * FindComponent, unless the directory is corrupted.
  374.          */
  375.         Fsutil_HandleRelease(parentHandlePtr, (status != SUCCESS));
  376.         parentHandlePtr = (Fsio_FileIOHandle *)NIL;
  377.         }
  378.     } else if ((compLen == 1) && component[0] == '.') {
  379.         /*
  380.          * Just hang tight with . (dot) because we already
  381.          * have a locked handle for it.
  382.          */
  383.     } else {
  384.         /*
  385.          * Advance to the next component and keep the handle on
  386.          * the parent locked so we can do deletes and creates.
  387.          */
  388.         if (parentHandlePtr != (Fsio_FileIOHandle *)NIL) {
  389.         Fsutil_HandleRelease(parentHandlePtr, TRUE);
  390.         }
  391.         parentHandlePtr = curHandlePtr;
  392.         status = FindComponent(parentHandlePtr, component, compLen, FALSE,
  393.             &curHandlePtr, &dirOffset);
  394.     }
  395.     /*
  396.      * At this point we have a locked handle on the current point
  397.      * in the lookup, and perhaps have a locked handle on the parent.
  398.      * Links are expanded now so we know whether or not the
  399.      * lookup is completed.  On the last component, we only
  400.      * expand the link if the FS_FOLLOW flag is present.
  401.      */
  402. #ifdef SOSP91
  403.     if (sospTraceCount<MAX_RECORDS && curHandlePtr !=
  404.         (Fsio_FileIOHandle *)NIL) {
  405.         bcopy((Address)curHandlePtr, (Address)sospTracePtr,
  406.             sizeof(Fs_FileID));
  407.         sospTracePtr++;
  408.         sospTraceCount++;
  409.     }
  410. #endif
  411.     if ((status == SUCCESS) &&
  412.         ((*curCharPtr != '\0') || (useFlags & FS_FOLLOW)) &&
  413.         ((curHandlePtr->descPtr->fileType == FS_SYMBOLIC_LINK ||
  414.         curHandlePtr->descPtr->fileType == FS_REMOTE_LINK))) {
  415.         numLinks++;
  416.         fs_Stats.lookup.symlinks++;
  417.         if (numLinks > FS_MAX_LINKS) {
  418.         status = FS_NAME_LOOP;
  419.         } else {
  420.         /*
  421.          * An extra buffer is used because the caller probably only
  422.          * has a buffer just big enough for the name.
  423.          */
  424.         int     offset;        /* Distance of existing name from
  425.                      * the start of its buffer */
  426.         if (newNameBuffer == (char *)NIL) {
  427.             offset = (int)curCharPtr - (int)relativeName;
  428.             newNameBuffer = (char *)malloc(FS_MAX_PATH_NAME_LENGTH);
  429.         } else {
  430.             offset = (int)curCharPtr - (int)newNameBuffer;
  431.         }
  432.         status = ExpandLink(curHandlePtr, curCharPtr, offset,
  433.                             newNameBuffer);
  434.         if (status == FS_FILE_NOT_FOUND) {
  435.             printf( "FslclLookup, empty link \"%s\"\n",
  436.                 relativeName);
  437.         }
  438.         curCharPtr = newNameBuffer;
  439.         }
  440.         if (status == SUCCESS) {
  441.         /*
  442.          * (Note: One could enforce permissions on links here.)
  443.          * If the link is back to the root we have to REDIRECT,
  444.          * otherwise retreat the current point in the lookup to
  445.          * the parent directory before continuing.
  446.          */
  447.         if (*curCharPtr == '/') {
  448.             *newNameInfoPtrPtr = mnew(Fs_RedirectInfo);
  449.             (void)strcpy((*newNameInfoPtrPtr)->fileName, curCharPtr);
  450.             status = FS_LOOKUP_REDIRECT;
  451.             /*
  452.              * Return the length of the prefix indicated by
  453.              * a remote link, zero means no prefix.
  454.              */
  455.             if (curHandlePtr->descPtr->fileType == FS_REMOTE_LINK) {
  456.             fs_Stats.lookup.remote++;
  457.             (*newNameInfoPtrPtr)->prefixLength = 
  458.                         curHandlePtr->descPtr->lastByte;
  459.             } else {
  460.             fs_Stats.lookup.redirect++;
  461.             (*newNameInfoPtrPtr)->prefixLength = 0;
  462.             }
  463.         } else if (parentHandlePtr != (Fsio_FileIOHandle *)NIL) {
  464. #ifdef SOSP91
  465.             /*
  466.              * Put an indication in the trace that we hit a link.
  467.              */
  468.             if (sospTraceCount<MAX_RECORDS && curHandlePtr !=
  469.                 (Fsio_FileIOHandle *)NIL) {
  470.             ((int *)sospTracePtr)[0] = -1;
  471.             ((int *)sospTracePtr)[1] = -2;
  472.             ((int *)sospTracePtr)[2] = -3;
  473.             ((int *)sospTracePtr)[3] = -4;
  474.             sospTracePtr++;
  475.             sospTraceCount++;
  476.             }
  477. #endif
  478.             Fsutil_HandleRelease(curHandlePtr, TRUE);
  479.             curHandlePtr = parentHandlePtr;
  480.             parentHandlePtr = (Fsio_FileIOHandle *)NIL;
  481.             status = SUCCESS;
  482.         } else {
  483.             panic( "No parent after link");
  484.             status = FS_INVALID_ARG;
  485.         }
  486.         }
  487.     }
  488.     }
  489. endScan:
  490.     if (useFlags & FSUTIL_TRACE_FLAG) {
  491.     FSUTIL_TRACE_NAME(FSUTIL_TRACE_LOOKUP_DONE, relativeName);
  492.     }
  493.     if ((status == SUCCESS) ||
  494.     ((status == FS_FILE_NOT_FOUND) && (*curCharPtr == '\0'))) {
  495.     /*
  496.      * Done with the lookup.  Determine the type of the file once
  497.      * we have a handle for it if its type is not already set from the
  498.      * file descriptor. Process creates, links, and deletes.
  499.      */
  500.     switch(useFlags & (FS_CREATE|FS_DELETE|FS_LINK)) {
  501.         case 0:
  502.         if (status == SUCCESS) {
  503.             /*
  504.              * Normal lookup completion.
  505.              */
  506.             status = CheckPermissions(curHandlePtr, useFlags, idPtr,
  507.                         type);
  508.         }
  509.         break;
  510.         case FS_CREATE:
  511.         fs_Stats.lookup.forCreate++;
  512.         if (status == SUCCESS && (useFlags & FS_EXCLUSIVE)) {
  513.             /*
  514.              * FS_EXCLUSIVE and FS_CREATE means that the file
  515.              * cannot already exist.
  516.              */
  517.             status = FS_FILE_EXISTS;
  518.         } else if (status == FS_FILE_NOT_FOUND) {
  519.             /*
  520.              * 'component' is the last part of a pathname for a
  521.              * file we need to create and that doesn't exist.
  522.              * Check for write permission in the parent directory,
  523.              * choose a fileNumber for the new file, and then
  524.              * create the file itself.
  525.              */
  526.             int     newFileNumber;
  527.             int     nearbyFile;
  528.  
  529.             status = CheckPermissions(parentHandlePtr, FS_WRITE, idPtr,
  530.                             FS_DIRECTORY);
  531.             if (status == SUCCESS) {
  532.             int logOp;
  533.             dirFileNumber = parentHandlePtr->hdr.fileID.minor;
  534.             newFileNumber = -1;
  535.             dirOffset = -1;
  536.             if (type == FS_DIRECTORY) {
  537.                 logOp = FSDM_LOG_CREATE|FSDM_LOG_IS_DIRECTORY;
  538.                 nearbyFile = -1;
  539.             } else {
  540.                 logOp = FSDM_LOG_CREATE;
  541.                 nearbyFile = dirFileNumber;
  542.             }
  543.             logClientData = Fsdm_DirOpStart(logOp,
  544.                       parentHandlePtr, dirOffset,
  545.                       component, compLen,
  546.                       newFileNumber, type,
  547.                       (Fsdm_FileDescriptor *) NIL);
  548.             status = Fsdm_GetNewFileNumber(domainPtr, nearbyFile,
  549.                                  &newFileNumber);
  550.             if (status == SUCCESS) {
  551.                 status = CreateFile(domainPtr, parentHandlePtr,
  552.                      component, compLen, newFileNumber, type,
  553.                      permissions, idPtr, &curHandlePtr,
  554.                      &dirOffset);
  555.                 if (status != SUCCESS) {
  556.                 (void)Fsdm_FreeFileNumber(domainPtr,
  557.                         newFileNumber);
  558.                 } 
  559.             }
  560.             if (status == SUCCESS) { 
  561.                 Fsdm_DirOpEnd(logOp, 
  562.                     parentHandlePtr, dirOffset,
  563.                     component, compLen, newFileNumber, type,
  564.                     curHandlePtr->descPtr, logClientData, 
  565.                     status);
  566.             } else {
  567.                 Fsdm_DirOpEnd(logOp, 
  568.                      parentHandlePtr, dirOffset,
  569.                      component, compLen, newFileNumber, type,
  570.                      (Fsdm_FileDescriptor *) NIL, 
  571.                      logClientData, status);
  572.             }
  573.             }
  574.         } else {
  575.             /*
  576.              * If the file exists, it's like a normal lookup completion
  577.              * and we have to check permissions.
  578.              */
  579.             status = CheckPermissions(curHandlePtr, useFlags, idPtr,
  580.                         type);
  581.         }
  582.         if (status == SUCCESS) {
  583.             (void)Fsdm_FileDescStore(curHandlePtr, FALSE);
  584.         }
  585.         break;
  586.         case FS_LINK: {
  587.         Boolean         fileDeleted = FALSE;
  588.         Fsio_FileIOHandle    *deletedHandlePtr;
  589.         /*
  590.          * The presence of FS_LINK means that curHandlePtr references
  591.          * a file that is being linked to.  If the file already exists
  592.          * it is deleted first.  Then link is made with LinkFile.
  593.          */
  594.         if (useFlags & FS_RENAME) {
  595.             logOp = FSDM_LOG_RENAME_LINK;
  596.             fs_Stats.lookup.forRename++;
  597.         } else {
  598.             logOp = FSDM_LOG_LINK;
  599.             fs_Stats.lookup.forLink++;
  600.         }
  601.         dirFileNumber = parentHandlePtr->hdr.fileID.minor;
  602.         if (status == SUCCESS) {
  603.             /*
  604.              * Linking to an existing file.
  605.              * This can only be in preparation for a rename.
  606.              */
  607.             if ((useFlags & FS_RENAME) &&
  608.             (curHandlePtr->descPtr->fileType == type)) {
  609.             /*
  610.              * Try the delete, this fails on non-empty directories.
  611.              */
  612.             deletedHandlePtr = curHandlePtr;
  613.             status = DeleteFileName(parentHandlePtr,
  614.                   curHandlePtr, component, compLen, FALSE, idPtr,
  615.                   FSDM_LOG_RENAME_DELETE);
  616.             if (status == SUCCESS) {
  617.                 fileDeleted = TRUE;
  618.             }
  619.             } else {
  620.             /*
  621.              * Not ok to link to an existing file.
  622.              */
  623.             status = FS_FILE_EXISTS;
  624.             }
  625.         } else if (status == FS_FILE_NOT_FOUND) {
  626.             /*
  627.              * The file does not already exist.  Check write permission
  628.              * in the parent before making the link.
  629.              */
  630.             status = CheckPermissions(parentHandlePtr, FS_WRITE, idPtr,
  631.                             FS_DIRECTORY);
  632.         }
  633.         if (status == SUCCESS) {
  634.             status = LinkFile(parentHandlePtr,
  635.                 component, compLen, fileNumber, logOp,
  636.                 &curHandlePtr);
  637.             if (status == SUCCESS) {
  638.             (void)Fsdm_FileDescStore(curHandlePtr, FALSE);
  639.             }
  640.         }
  641.         if (fileDeleted) {
  642.             CloseDeletedFile(&parentHandlePtr, &deletedHandlePtr);
  643.         }
  644.         break;
  645.         }
  646.         case FS_DELETE:
  647.         fs_Stats.lookup.forDelete++;
  648.         if (status == SUCCESS) {
  649.             if ((curHandlePtr->descPtr->fileType != type) &&
  650.             (type != FS_FILE)) {
  651.             status = (type == FS_DIRECTORY) ? FS_NOT_DIRECTORY :
  652.                               FS_WRONG_TYPE;
  653.             } else {
  654.             logOp = (useFlags&FS_RENAME) ? FSDM_LOG_RENAME_UNLINK :
  655.                                FSDM_LOG_UNLINK;
  656.             status = DeleteFileName(parentHandlePtr, 
  657.                 curHandlePtr, component, compLen,
  658.                 (int) (useFlags & FS_RENAME), idPtr, logOp);
  659.             if (status == SUCCESS) {
  660. #ifdef SOSP91
  661.             SOSP_ADD_DELETE_TRACE(clientID, 
  662.                 SOSP_REMEMBERED_MIG,  
  663.                 curHandlePtr->hdr.fileID,
  664.                 curHandlePtr->cacheInfo.attr.modifyTime,
  665.                 curHandlePtr->cacheInfo.attr.createTime,
  666.                 curHandlePtr->cacheInfo.attr.lastByte + 1);
  667. #endif
  668.  
  669.                 CloseDeletedFile(&parentHandlePtr,
  670.                     &curHandlePtr);
  671.             }
  672.             }
  673.         }
  674.         break;
  675.     }
  676.     }
  677.  
  678.     /*
  679.      * Clean up state and return a fileHandle to our caller.
  680.      */
  681.     if (newNameBuffer != (char *)NIL) {
  682.     free(newNameBuffer);
  683.     }
  684.     if (parentHandlePtr != (Fsio_FileIOHandle *)NIL) {
  685.     Fsutil_HandleRelease(parentHandlePtr, TRUE);
  686.     }
  687.     if (curHandlePtr != (Fsio_FileIOHandle *)NIL) {
  688.     if (status != SUCCESS) {
  689.         Fsutil_HandleRelease(curHandlePtr, TRUE);
  690.         curHandlePtr = (Fsio_FileIOHandle *)NIL;
  691.     } 
  692.     }
  693.     if (handlePtrPtr != (Fsio_FileIOHandle **)NIL) {
  694.     /*
  695.      * Return a locked handle that has had its reference count bumped.
  696.      */
  697.     *handlePtrPtr = curHandlePtr;
  698.     } else if (curHandlePtr != (Fsio_FileIOHandle *)NIL) {
  699.     printf( "FslclLookup: caller didn't want handle\n");
  700.     Fsutil_HandleRelease(curHandlePtr, TRUE);
  701.     }
  702.     if ((status != SUCCESS) ||
  703.     (handlePtrPtr == (Fsio_FileIOHandle **)NIL)) {
  704.     Fsdm_DomainRelease(prefixHdrPtr->fileID.major);
  705.     }
  706.     if (fslclComponentTrace && !fsprefix_FileNameTrace) {
  707.     printf(" <%x>\n", status);
  708.     }
  709.     if (status == FS_FILE_NOT_FOUND) {
  710.     fs_Stats.lookup.notFound++;
  711.     }
  712. #ifdef SOSP91
  713.     if (curHandlePtr != (Fsio_FileIOHandle *)NIL) {
  714.     SOSP_ADD_LOOKUP(((int *)buf), clientID,
  715.         (*(Fs_FileID *)(&(curHandlePtr->hdr))), status, sospTraceCount,
  716.         SOSP_REMEMBERED_MIG,
  717.         SOSP_REMEMBERED_OP|(curHandlePtr->descPtr->fileType<<8));
  718.     } else {
  719.     SOSP_ADD_LOOKUP(((int *)buf), clientID,
  720.         NullFileID, status, sospTraceCount,
  721.         SOSP_REMEMBERED_MIG, SOSP_REMEMBERED_OP);
  722.     }
  723.     SOSP_REMEMBERED_CLIENT = -1;
  724.     SOSP_REMEMBERED_MIG = -1;
  725.     SOSP_REMEMBERED_OP = -1;
  726.     SOSP_IN_NAME_LOOKUP_FIELD = 0;
  727.     Timer_GetCurrentTicks(&endTicks);
  728.     Timer_SubtractTicks(endTicks, startTicks, &endTicks);
  729.     /* Should really have a lock here, but I'll trust that this works. */
  730.     Timer_AddTicks(totalNameTime, endTicks, &totalNameTime);
  731. #endif
  732.     return(status);
  733. }
  734.  
  735.  
  736. /*
  737.  *----------------------------------------------------------------------
  738.  *
  739.  * FindComponent --
  740.  *
  741.  *    Look for a pathname component in a directory.  This returns a locked
  742.  *    file handle that has its reference count incremented.
  743.  *
  744.  * Results:
  745.  *    SUCCESS or FS_FILE_NOT_FOUND
  746.  *
  747.  * Side effects:
  748.  *    Disk I/O, installing and locking the handle.
  749.  *
  750.  *----------------------------------------------------------------------
  751.  */
  752. static ReturnStatus
  753. FindComponent(parentHandlePtr, component, compLen, isDotDot, curHandlePtrPtr,
  754.           dirOffsetPtr)
  755.     Fsio_FileIOHandle    *parentHandlePtr;    /* Locked handle of current 
  756.                          * directory */
  757.     register char     *component;        /* Name of path component to 
  758.                          * find */
  759.     register int     compLen;        /* The number of characters in 
  760.                          * component */
  761.     Boolean        isDotDot;        /* TRUE if component is "..".
  762.                          * In this case the handle for
  763.                          * the parent is returned
  764.                          * UNLOCKED. */
  765.     Fsio_FileIOHandle    **curHandlePtrPtr;    /* Return, locked handle */
  766.     int            *dirOffsetPtr;        /* OUT: Offset into directory
  767.                          * off component. */
  768. {
  769.     register Fslcl_DirEntry *dirEntryPtr;    /* Reference to directory entry */
  770.     register char    *s1;        /* Pointers into components used */
  771.     register char    *s2;        /*   for fast in-line string compare */
  772.     register int     blockOffset;    /* Offset within the directory */
  773.     ReturnStatus     status;
  774.     Fscache_Block    *cacheBlockPtr;    /* Cache block */
  775.     int         dirBlockNum;    /* Block number within directory */
  776.     int         length;        /* Length variable for read call */
  777.     FslclHashEntry        *entryPtr;    /* Name cache entry */
  778.     Fs_FileID        fileID;        /* Used when fetching handles */
  779.  
  780.     /*
  781.      * Check in system-wide name cache here before scanning
  782.      * the directory's data blocks.
  783.      */
  784.     entryPtr = FSLCL_HASH_LOOK_ONLY(fslclNameTablePtr, component, parentHandlePtr);
  785.     if (entryPtr != (FslclHashEntry *)NIL) {
  786.     if (entryPtr->hdrPtr->fileID.type != FSIO_LCL_FILE_STREAM) {
  787.         panic(
  788.               "FindComponent: got trashy handle from cache");
  789.     } else {
  790.         if (isDotDot) {
  791.         /*
  792.          * Unlock this directory before grabbing the handle for "..".
  793.          * This prevents deadlock with another lookup that is
  794.          * descending from our parent ("..") into this directory.
  795.          */
  796.         Fsutil_HandleUnlock(parentHandlePtr);
  797.         }
  798.         *curHandlePtrPtr = Fsutil_HandleDupType(Fsio_FileIOHandle,
  799.                         entryPtr->hdrPtr);
  800.         return(SUCCESS);
  801.     }
  802.     }
  803.  
  804.     dirBlockNum = 0;
  805.     do {
  806.     status = Fscache_BlockRead(&parentHandlePtr->cacheInfo, dirBlockNum,
  807.             &cacheBlockPtr, &length, FSCACHE_DIR_BLOCK, FALSE);
  808.     if (status != SUCCESS || length == 0) {
  809.         *curHandlePtrPtr = (Fsio_FileIOHandle *)NIL;
  810.         return(FS_FILE_NOT_FOUND);
  811.     }
  812.     dirEntryPtr = (Fslcl_DirEntry *)cacheBlockPtr->blockAddr;
  813.     blockOffset = 0;
  814.     while (blockOffset < length) {
  815.         if (dirEntryPtr->recordLength <= 0) {
  816.         printf("Corrupted directory?");
  817.         printf(" File ID <%d, %d, %d>",
  818.                  parentHandlePtr->hdr.fileID.serverID,
  819.                  parentHandlePtr->hdr.fileID.major,
  820.                  parentHandlePtr->hdr.fileID.minor);
  821.         printf(" dirBlockNum <%d>, blockOffset <%d>",
  822.                  dirBlockNum, blockOffset);
  823.         printf("\n");
  824.         Fscache_UnlockBlock(cacheBlockPtr, 0, -1, 0,
  825.                     FSCACHE_CLEAR_READ_AHEAD);
  826.         *curHandlePtrPtr = (Fsio_FileIOHandle *)NIL;
  827.         return(FS_FILE_NOT_FOUND);
  828.         }
  829.  
  830.         if (dirEntryPtr->fileNumber != 0) {
  831.         /*
  832.          * A valid directory record.  If component and the directory
  833.          * entry are the same length then compare them for a match.
  834.          * This String Compare is in-lined for efficiency.
  835.          */
  836.         if ((dirEntryPtr->nameLength == compLen)) {
  837.             s1 = component;
  838.             s2 = dirEntryPtr->fileName;
  839.             do {
  840.             if (*s1 == '\0') {
  841.                 /*
  842.                  * The strings are the same length so hitting
  843.                  * the end of component indicates a match.
  844.                  */
  845.                 if (isDotDot) {
  846.                 /*
  847.                  * Unlock this directory before grabbing the
  848.                  * handle for "..".  This prevents deadlock
  849.                  * with another lookup that is descending
  850.                  * from our parent ("..") into this directory.
  851.                  */
  852.                 Fsutil_HandleUnlock(parentHandlePtr);
  853.                 }
  854.                 *dirOffsetPtr = blockOffset + 
  855.                     dirBlockNum * FS_BLOCK_SIZE;
  856.                 /*
  857.                  * Inlined call to GetHandle().
  858.                  */
  859.                 fileID.type = FSIO_LCL_FILE_STREAM;
  860.                 fileID.serverID = rpc_SpriteID;
  861.                 fileID.major = parentHandlePtr->hdr.fileID.major;
  862.                 fileID.minor = dirEntryPtr->fileNumber;
  863.                 status = Fsio_LocalFileHandleInit(&fileID, component,
  864.                         (Fsdm_FileDescriptor *) NIL, FALSE,
  865.                         curHandlePtrPtr);
  866.  
  867.                 Fscache_UnlockBlock(cacheBlockPtr, 0, -1, 0,
  868.                            FSCACHE_CLEAR_READ_AHEAD);
  869.                 if (status == SUCCESS) {
  870.                 FSLCL_HASH_INSERT(fslclNameTablePtr, component,
  871.                          parentHandlePtr, *curHandlePtrPtr);
  872.                 } else {
  873.                 /*
  874.                  * It is possible that the file doesn't 
  875.                  * exist anymore.  This happens when
  876.                  * the parent directory of an open
  877.                  * directory is deleted.  The ".." entry
  878.                  * points to a deleted file.
  879.                  */
  880.                 if (status == FS_FILE_REMOVED) {
  881.                     status = FS_FILE_NOT_FOUND;
  882.                 } else {
  883.  
  884.                     printf(
  885.         "FindComponent, no handle <0x%x> for \"%s\" fileNumber %d\n",
  886.                     status, component, dirEntryPtr->fileNumber);
  887.                 }
  888.                 if (isDotDot) {
  889.                     /*
  890.                      * If we have an error, relock the handle
  891.                      * because your caller will assume that it
  892.                      * is locked.
  893.                      */
  894.                     Fsutil_HandleLock(parentHandlePtr);
  895.                 }
  896.                 }
  897.                 goto exit;    /* to quiet lint... */
  898. #ifndef lint
  899.             } else if (*s1++ != *s2++) {
  900.                 break;
  901. #else
  902.             } else {
  903.                 if (*s1 != *s2) {
  904.                 break;
  905.                 }
  906.                 s1++;
  907.                 s2++;
  908. #endif
  909.             }
  910.             } while (TRUE);
  911.         }
  912.         }
  913.         blockOffset += dirEntryPtr->recordLength;
  914.         dirEntryPtr = (Fslcl_DirEntry *)((int)dirEntryPtr +
  915.                      dirEntryPtr->recordLength);
  916.     }
  917.     dirBlockNum++;
  918.     Fscache_UnlockBlock(cacheBlockPtr, 0, -1, 0, 0);
  919.     } while(TRUE);
  920. exit:
  921.     return(status);
  922. }
  923.  
  924.  
  925. /*
  926.  *----------------------------------------------------------------------
  927.  *
  928.  * InsertComponent --
  929.  *    Add a name to a directory.
  930.  *
  931.  * Results:
  932.  *    SUCCESS or an error code.
  933.  *
  934.  * Side effects:
  935.  *    Adding the name to the directory, writing the modified directory block.
  936.  *
  937.  *----------------------------------------------------------------------
  938.  */
  939. static ReturnStatus
  940. InsertComponent(curHandlePtr, component, compLen, fileNumber, dirOffsetPtr)
  941.     Fsio_FileIOHandle *curHandlePtr;    /* Locked handle of current directory */
  942.     char *component;            /* Name of path component to insert */
  943.     int compLen;            /* The length of component */
  944.     int fileNumber;            /* File Number of inserted name */
  945.     int    *dirOffsetPtr;  /* OUT: directory offset of component's entry.*/
  946. {
  947.     ReturnStatus     status;
  948.     int            dirBlockNum;    /* Directory block index */
  949.     int         blockOffset;    /* Offset within a directory block. */
  950.     Fslcl_DirEntry         *dirEntryPtr;    /* Reference to directory entry. */
  951.     int         length;        /* Length variable for read call. */
  952.     int         recordLength;    /* Length of directory entry for 
  953.                      * component. */
  954.     int         freeSpace;    /* Total amount of free bytes in a 
  955.                      * directory block. */
  956.     int         extraBytes;    /* The number of free bytes attached to
  957.                       * a directory entry. */
  958.     Fscache_Block    *cacheBlockPtr;    /* Cache block. */
  959.  
  960.     length = FS_BLOCK_SIZE;
  961.     recordLength = Fslcl_DirRecLength(compLen);
  962.     /*
  963.      * Loop through the directory blocks looking for space of at least
  964.      * recordLength in which to insert the new directory record.
  965.      */
  966.     dirBlockNum = 0;
  967.     do {
  968.     /*
  969.      * Read in a full data block.
  970.      */
  971.     status = Fscache_BlockRead(&curHandlePtr->cacheInfo, dirBlockNum,
  972.             &cacheBlockPtr, &length, FSCACHE_DIR_BLOCK, TRUE);
  973.     if (status != SUCCESS) {
  974.         printf( "InsertComponent: Read failed\n");
  975.         return(status);
  976.     } else if (length == 0) {
  977.         /*
  978.          * No more space, have to grow the directory.  First we
  979.          * need another cache block.
  980.          */
  981.         Boolean found = FALSE;
  982.  
  983.         Fscache_FetchBlock(&curHandlePtr->cacheInfo, dirBlockNum,
  984.                 FSCACHE_DIR_BLOCK, &cacheBlockPtr, &found);
  985.         if (found) {
  986.         panic( "InsertComponent found new dir block");
  987.         }
  988.         bzero(cacheBlockPtr->blockAddr, FS_BLOCK_SIZE);
  989.     }
  990.  
  991.     dirEntryPtr = (Fslcl_DirEntry *)cacheBlockPtr->blockAddr;
  992.     blockOffset = 0;
  993.     freeSpace = 0;
  994.     while (blockOffset < length) {
  995.         /*
  996.          * Scan a data block looking for deleted entries that are
  997.          * large enough to use, or for entries that contain enough extra
  998.          * bytes for the record we have to insert.  The amount of fragmented
  999.          * space is accumulated in freeSpace but compaction is not 
  1000.          * implemented.
  1001.          */
  1002.         if (dirEntryPtr->fileNumber != 0) {
  1003.         /*
  1004.          * A valid directory record.
  1005.          * Check the left-over bytes attached to this record.
  1006.          */
  1007.         extraBytes = dirEntryPtr->recordLength -
  1008.                  Fslcl_DirRecLength(dirEntryPtr->nameLength);
  1009.         if (extraBytes >= recordLength) {
  1010.             /*
  1011.              * Can fit new entry in the space left over.
  1012.              */ 
  1013.             goto haveASlot;
  1014.         }
  1015.         /*
  1016.          * Count bytes that occur in fragments of 4 bytes or more.
  1017.          */
  1018.         freeSpace += extraBytes & ~(FSLCL_REC_LEN_GRAIN-1);
  1019.         } else {
  1020.         /*
  1021.          * A deleted name in the directory.
  1022.          */
  1023.         if (dirEntryPtr->recordLength >= recordLength) {
  1024.             goto haveASlot;
  1025.         }
  1026.         freeSpace += dirEntryPtr->recordLength;
  1027.         }
  1028.         blockOffset += dirEntryPtr->recordLength;
  1029.         dirEntryPtr = (Fslcl_DirEntry *)((int)dirEntryPtr +
  1030.                      dirEntryPtr->recordLength);
  1031.     }
  1032.     /*
  1033.      * Finished scanning a directory block.  Note if the accumulated
  1034.      * free bytes in the block could be used for a directory entry.
  1035.      * (We aren't implementing compaction for a while yet...)
  1036.      */
  1037.     if (freeSpace >= recordLength) {
  1038.         fsCompacts++;
  1039.     }
  1040.     if (length < FS_BLOCK_SIZE) {
  1041.         /*
  1042.          * Scanned up to the end of the last directory data block.  Need
  1043.          * to append to the end of the directory.
  1044.          */
  1045.         bzero(cacheBlockPtr->blockAddr + length, FSLCL_DIR_BLOCK_SIZE);
  1046.         dirEntryPtr->recordLength = FSLCL_DIR_BLOCK_SIZE;
  1047.         length += FSLCL_DIR_BLOCK_SIZE;
  1048.         break;
  1049.     }
  1050.  
  1051.     dirBlockNum++;
  1052.     Fscache_UnlockBlock(cacheBlockPtr, 0, -1, 0, FSCACHE_CLEAR_READ_AHEAD);
  1053.     } while(TRUE);
  1054.  
  1055. haveASlot:
  1056.  
  1057.     /*
  1058.      * At this point dirEntryPtr references the slot we have to either re-use
  1059.      * or that has enough free bytes for us to use.
  1060.      */
  1061.     if (dirEntryPtr->fileNumber != 0) {
  1062.     /*
  1063.      * Have to take space away from the end of a valid directory entry.
  1064.      */
  1065.     int newRecordLength;    /* New length of the existing valid entry */
  1066.     Fslcl_DirEntry *tmpDirEntryPtr;    /* Pointer to new slot */
  1067.  
  1068.     newRecordLength = Fslcl_DirRecLength(dirEntryPtr->nameLength);
  1069.     tmpDirEntryPtr = (Fslcl_DirEntry *)((int)dirEntryPtr + newRecordLength);
  1070.     tmpDirEntryPtr->recordLength = dirEntryPtr->recordLength -
  1071.                        newRecordLength;
  1072.     dirEntryPtr->recordLength = newRecordLength;
  1073.     dirEntryPtr = tmpDirEntryPtr;
  1074.     }
  1075.     dirEntryPtr->fileNumber = fileNumber;
  1076.     dirEntryPtr->nameLength = compLen;
  1077.     (void)strcpy(dirEntryPtr->fileName, component);
  1078.  
  1079.     blockOffset = (((char *)dirEntryPtr) - (char *)(cacheBlockPtr->blockAddr));
  1080.     *dirOffsetPtr = dirBlockNum * FS_BLOCK_SIZE + blockOffset;
  1081.     status = CacheDirBlockWrite(curHandlePtr,cacheBlockPtr,dirBlockNum,length);
  1082.     return(status);
  1083. }
  1084.  
  1085.  
  1086. /*
  1087.  *----------------------------------------------------------------------
  1088.  *
  1089.  * DeleteComponent --
  1090.  *
  1091.  *    Delete a name from a directory.  The file descriptor itself
  1092.  *    is not modified.  It is assumed that the handle for the file that
  1093.  *    is being removed is already locked.
  1094.  *
  1095.  * Results:
  1096.  *    SUCCESS or FS_FILE_NOT_FOUND
  1097.  *
  1098.  * Side effects:
  1099.  *    Sets the fileNumber for the component to Zero (0) to mark as deleted.
  1100.  *
  1101.  *----------------------------------------------------------------------
  1102.  */
  1103. static ReturnStatus
  1104. DeleteComponent(parentHandlePtr, component, compLen, dirOffsetPtr)
  1105.     Fsio_FileIOHandle    *parentHandlePtr;/* Locked handle of current dir. */
  1106.     char         *component;    /* Name to delete */
  1107.     int         compLen;    /* Length of the name */
  1108.     int            *dirOffsetPtr;    /* OUT: Directory offset of component.*/
  1109. {
  1110.     ReturnStatus    status;
  1111.     int         blockOffset;    /* Offset within a directory block */
  1112.     Fslcl_DirEntry     *dirEntryPtr;    /* Reference to directory entry */
  1113.     Fslcl_DirEntry     *lastDirEntryPtr;/* Back pointer used when merging 
  1114.                       * adjacent entries after the delete */
  1115.     int         length;        /* Length variable for read call */
  1116.     Fscache_Block    *cacheBlockPtr;    /* Cache block. */
  1117.     int            dirBlockNum;
  1118.  
  1119.     dirBlockNum = 0;
  1120.     do {
  1121.     status = Fscache_BlockRead(&parentHandlePtr->cacheInfo, dirBlockNum,
  1122.               &cacheBlockPtr, &length, FSCACHE_DIR_BLOCK, FALSE);
  1123.     if (status != SUCCESS || length == 0) {
  1124.         return(FS_FILE_NOT_FOUND);
  1125.     }
  1126.     blockOffset = 0;
  1127.     lastDirEntryPtr = (Fslcl_DirEntry *)NIL;
  1128.     dirEntryPtr = (Fslcl_DirEntry *)cacheBlockPtr->blockAddr;
  1129.     while (blockOffset < length) {
  1130.         if ((dirEntryPtr->fileNumber != 0) &&
  1131.         (dirEntryPtr->nameLength == compLen) &&
  1132.         (strcmp(component, dirEntryPtr->fileName) == 0)) {
  1133.         /*
  1134.          * Delete the entry from the name cache.
  1135.          */
  1136.         *dirOffsetPtr = blockOffset + FS_BLOCK_SIZE*dirBlockNum;
  1137.         FSLCL_HASH_DELETE(fslclNameTablePtr, component,parentHandlePtr);
  1138.         dirEntryPtr->fileNumber = 0;
  1139.         if (lastDirEntryPtr != (Fslcl_DirEntry *)NIL) {
  1140.             /*
  1141.              * Grow the previous record so that it now includes
  1142.              * this one.
  1143.              */
  1144.             lastDirEntryPtr->recordLength += dirEntryPtr->recordLength;
  1145.         }
  1146.         /*
  1147.          * Write out the modified directory block.
  1148.          */
  1149.         status = CacheDirBlockWrite(parentHandlePtr, cacheBlockPtr, 
  1150.                        dirBlockNum, length);
  1151.         return(status);
  1152.         }
  1153.         blockOffset += dirEntryPtr->recordLength;
  1154.         if ((blockOffset & (FSLCL_DIR_BLOCK_SIZE - 1)) == 0) {
  1155.          lastDirEntryPtr = (Fslcl_DirEntry *) NIL;
  1156.         } else {
  1157.          lastDirEntryPtr = dirEntryPtr;
  1158.         }
  1159.         dirEntryPtr = 
  1160.         (Fslcl_DirEntry *)((int)dirEntryPtr + dirEntryPtr->recordLength);
  1161.     }
  1162.     dirBlockNum++;
  1163.     Fscache_UnlockBlock(cacheBlockPtr, 0, -1, 0, FSCACHE_CLEAR_READ_AHEAD);
  1164.     } while(TRUE);
  1165.     /*NOTREACHED*/
  1166. }
  1167.  
  1168.  
  1169. /*
  1170.  *----------------------------------------------------------------------
  1171.  *
  1172.  * ExpandLink --
  1173.  *    Expand a link by shifting the remaining pathname over and
  1174.  *    inserting the contents of the link file.
  1175.  *
  1176.  * Results:
  1177.  *    None.
  1178.  *
  1179.  * Side effects:
  1180.  *    Expands the link into nameBuffer.
  1181.  *
  1182.  *----------------------------------------------------------------------
  1183.  */
  1184. static ReturnStatus
  1185. ExpandLink(curHandlePtr, curCharPtr, offset, nameBuffer)
  1186.     Fsio_FileIOHandle    *curHandlePtr;    /* Handle on the link file */
  1187.     char    *curCharPtr;        /* Points to beginning of the remaining
  1188.                      * name that has to be shifted */
  1189.     int        offset;            /* Offset of curCharPtr within its 
  1190.                      * buffer */
  1191.     char     nameBuffer[];        /* New buffer for the expanded name */
  1192. {
  1193.     ReturnStatus     status;
  1194.     int         linkNameLength;    /* The length of the name in the
  1195.                      * link NOT including the Null */
  1196.     register char     *srcPtr;
  1197.     register char     *dstPtr;
  1198.  
  1199.     linkNameLength = curHandlePtr->descPtr->lastByte;    /* + 1 */
  1200.     if (linkNameLength < 0) {                /* <= */
  1201.     return(FS_FILE_NOT_FOUND);
  1202.     }
  1203.     if (*curCharPtr == '\0') {
  1204.     /*
  1205.      * There is no pathname, just make sure the new name is Null terminated
  1206.      */
  1207.     nameBuffer[linkNameLength] = '\0';        /* still ok */
  1208.     } else {
  1209.     /*
  1210.      * Set up srcPtr to point to the start of the remaining pathname.
  1211.      * Set up dstPtr to point to just after where the link will be,
  1212.      * ie. just where the '/' is that separates the link value from
  1213.      * the remaining pathname.
  1214.      */
  1215.     srcPtr = curCharPtr;
  1216.     dstPtr = &nameBuffer[linkNameLength];
  1217.     if (linkNameLength < offset) {
  1218.         /*
  1219.          * The remaining name has to be shifted left.
  1220.          * For example, /first is a link to /usr (or /users).  With the
  1221.          * filename /first/abc, curCharPtr will point to the 'a' in "abc".
  1222.          * dstPtr points to the '\0' after "/usr".
  1223.          *
  1224.          *  / f i r s t / a b c \0        { current name, offset = 7 }
  1225.          *  / u s r \0            { link name, len = 4 }
  1226.          *  / u s e r s \0            {   or len = 6 }
  1227.          *  / u s r / a b c            { final result }
  1228.          *
  1229.          * Insert the separating '/' first, then start at the beginning
  1230.          * of the remaining name and copy it into the new buffer.
  1231.          */
  1232.         *dstPtr = '/';
  1233.         dstPtr++;
  1234.         for( ; ; ) {
  1235.         *dstPtr = *srcPtr;
  1236.             if (*srcPtr == '\0') {
  1237.             break;
  1238.         }
  1239.         dstPtr++;
  1240.         srcPtr++;
  1241.         }
  1242.     } else {
  1243.         /*
  1244.          * The remaining name has to be shifted right.
  1245.          * For example, /first is a link to /usr/tmp.  With the filename
  1246.          * /first/abc, curCharPtr will point to the 'a' in "abc".
  1247.          * dstPtr points to the '\0' after "/usr/tmp".
  1248.          *
  1249.          * / f i r s t / a b c \0        { current name, offset = 7 }
  1250.          * / u s r / t m p \0        { link name, len = 8 }
  1251.          * / u s r / t m p / a b c        { final result }
  1252.          * 
  1253.          * Zoom to the end of the name (adjusting dstPtr to account
  1254.          * for where the '/' will go) and then shift the name right.
  1255.          */
  1256.         dstPtr++;
  1257.         while (*srcPtr != '\0') {
  1258.         srcPtr++;
  1259.         dstPtr++;
  1260.         }
  1261.         while (srcPtr >= curCharPtr) {
  1262.         *dstPtr = *srcPtr;
  1263.         dstPtr--;
  1264.         srcPtr--;
  1265.         }
  1266.         *dstPtr = '/';
  1267.     }
  1268.     }
  1269.     /*
  1270.      * Read and insert the link name in front of the remaining name
  1271.      * that was just shifted over.
  1272.      */
  1273.     status = Fscache_Read(&curHandlePtr->cacheInfo, 0, nameBuffer, 0,
  1274.             &linkNameLength, (Sync_RemoteWaiter *)NIL);
  1275.     if ((status == SUCCESS) || (linkNameLength > 0)) { 
  1276.     (void)Fsdm_UpdateDescAttr(curHandlePtr, &curHandlePtr->cacheInfo.attr, 
  1277.             FSDM_FD_ACCESSTIME_DIRTY);
  1278.     }
  1279.  
  1280.     /*
  1281.      * FIX HERE to handle old sprite links that include a null.
  1282.      */
  1283. #ifdef notdef
  1284.     if (nameBuffer[linkNameLength-1] == '\0') {
  1285.     /*
  1286.      * Old Sprite link with trailing NULL.  Shift remaining name over
  1287.      * to the left one place.
  1288.      */
  1289.     dstPtr = &nameBuffer[linkNameLength-1];
  1290.     srcPtr = dstPtr + 1;
  1291.     while (*srcPtr != '\0') {
  1292.         *dstPtr++ = *srcPtr++;
  1293.     }
  1294.     *dstPtr = '\0'
  1295.     }
  1296. #endif /* notdef */
  1297.     return status;
  1298. }
  1299.  
  1300. /*
  1301.  *----------------------------------------------------------------------
  1302.  *
  1303.  * GetHandle --
  1304.  *
  1305.  *    Given a file number and the handle on the parent directotry,
  1306.  *    this routine returns a locked handle for the file.  This is a
  1307.  *    small layer on top of Fsio_LocalFileHandleInit that is oriented
  1308.  *    towards the needs of the lookup routines.
  1309.  *
  1310.  * Results:
  1311.  *    A return code.  If SUCCESS the returned handle is locked.
  1312.  *
  1313.  * Side effects:
  1314.  *    Calls Fsio_LocalFileHandleInit to set up the handle.
  1315.  *
  1316.  *----------------------------------------------------------------------
  1317.  */
  1318.  
  1319. static ReturnStatus
  1320. GetHandle(fileNumber, newDescPtr, curHandlePtr, name, newHandlePtrPtr)
  1321.     int        fileNumber;        /* Number of file to get handle for */
  1322.     Fsdm_FileDescriptor *newDescPtr;
  1323.     Fsio_FileIOHandle    *curHandlePtr;    /* Handle on file in the same domain */
  1324.     char    *name;            /* File name for error msgs */
  1325.     Fsio_FileIOHandle    **newHandlePtrPtr;/* Return, ref. to installed handle */
  1326. {
  1327.     register ReturnStatus status;
  1328.     Fs_FileID fileID;
  1329.  
  1330.     fileID.type = FSIO_LCL_FILE_STREAM;
  1331.     fileID.serverID = rpc_SpriteID;
  1332.     fileID.major = curHandlePtr->hdr.fileID.major;
  1333.     fileID.minor = fileNumber;
  1334.     status = Fsio_LocalFileHandleInit(&fileID, name, newDescPtr, FALSE,
  1335.         newHandlePtrPtr);
  1336.     return(status);
  1337. }
  1338.  
  1339. /*
  1340.  *----------------------------------------------------------------------
  1341.  *
  1342.  * CreateFile --
  1343.  *      Create a file by adding it do a directory and and initializing its
  1344.  *      file descriptor.  The caller has already allocated the fileNumber
  1345.  *      for the file.  The file descriptor is written to disk before the
  1346.  *    name is inserted into the directory.
  1347.  *
  1348.  * Results:
  1349.  *    SUCCESS or an error code.
  1350.  *
  1351.  * Side effects:
  1352.  *    Calls InsertComponent, Fsdm_FileDescInit.
  1353.  *
  1354.  *----------------------------------------------------------------------
  1355.  */
  1356. static ReturnStatus
  1357. CreateFile(domainPtr, parentHandlePtr, component, compLen, fileNumber, type,
  1358.        permissions, idPtr, curHandlePtrPtr, dirOffsetPtr)
  1359.     Fsdm_Domain    *domainPtr;        /* Domain of the file */
  1360.     Fsio_FileIOHandle    *parentHandlePtr;/* Handle of directory in which to add 
  1361.                      * file. */
  1362.     char    *component;        /* Name of the file */
  1363.     int        compLen;        /* The length of component */
  1364.     int        fileNumber;        /* Domain relative file number */
  1365.     int        type;            /* Type of the file */
  1366.     int        permissions;        /* Permission bits on the file */
  1367.     Fs_UserIDs    *idPtr;            /* User ID of calling process */
  1368.     Fsio_FileIOHandle    **curHandlePtrPtr;/* Return, handle for the new file */
  1369.     int        *dirOffsetPtr;  /* OUT: directory offset of component's entry.*/
  1370. {
  1371.     ReturnStatus    status;
  1372.     Fsdm_FileDescriptor    *parentDescPtr;    /* Descriptor for the parent */
  1373.     Fsdm_FileDescriptor    *newDescPtr;    /* Descriptor for the new file */
  1374.  
  1375.     /*
  1376.      * Set up the file descriptor using the group ID from the parent directory.
  1377.      */
  1378.     parentDescPtr = parentHandlePtr->descPtr;
  1379.     newDescPtr = (Fsdm_FileDescriptor *)malloc(sizeof(Fsdm_FileDescriptor));
  1380.     status = Fsdm_FileDescInit(domainPtr, fileNumber, type, permissions,
  1381.                 idPtr->user, parentDescPtr->gid, newDescPtr);
  1382.     if (status == SUCCESS) {
  1383.     if (type == FS_DIRECTORY) {
  1384.         /*
  1385.          * Both the parent and the directory itself reference it.
  1386.          */
  1387.         newDescPtr->numLinks = 2;
  1388.         newDescPtr->flags |= FSDM_FD_LINKS_DIRTY;
  1389.     }
  1390.     /*
  1391.      * GetHandle does extra work because we already have the
  1392.      * file descriptor all set up...
  1393.      */
  1394.     status = GetHandle(fileNumber, newDescPtr, parentHandlePtr, component,
  1395.                 curHandlePtrPtr);
  1396.     if (status != SUCCESS) {
  1397.         /*
  1398.          * GetHandle shouldn't fail because we just wrote out
  1399.          * the file descriptor.
  1400.          */
  1401.         panic( "CreateFile: GetHandle failed\n");
  1402.     } else {
  1403.         if (type == FS_DIRECTORY) {
  1404.         status = WriteNewDirectory(*curHandlePtrPtr,
  1405.                         parentHandlePtr);
  1406.         }
  1407.         if (status == SUCCESS) {
  1408.         /*
  1409.          * Commit by adding the name to the directory.  If we crash
  1410.          * after this the file will show up and have a good
  1411.          * descriptor for itself on disk.
  1412.          */
  1413.         status = InsertComponent(parentHandlePtr, component,
  1414.                       compLen, fileNumber, dirOffsetPtr);
  1415.         if (type == FS_DIRECTORY) {
  1416.             if (status == SUCCESS) {
  1417.             /*
  1418.              * Update the parent directory to reflect
  1419.              * the addition of a new sub-directory.
  1420.              */
  1421.             parentDescPtr->numLinks++;
  1422.             parentDescPtr->descModifyTime = Fsutil_TimeInSeconds();
  1423.             parentDescPtr->flags |= FSDM_FD_LINKS_DIRTY;
  1424.                (void)Fsdm_FileDescStore(parentHandlePtr, FALSE);
  1425.             }
  1426.         }
  1427.         }
  1428.         if (status != SUCCESS) {
  1429.         /*
  1430.          * Couldn't add to the directory, no disk space perhaps.
  1431.          * Unwind by marking the file descriptor as free and
  1432.          * releasing the handle we've created.
  1433.          */
  1434.         printf("CreateFile: aborting create of %d (%s) in %d\n",
  1435.             fileNumber, component, 
  1436.             parentHandlePtr->hdr.fileID.minor);
  1437.         newDescPtr->flags = FSDM_FD_FREE;
  1438.         Fsutil_HandleRelease(*curHandlePtrPtr, TRUE);
  1439.         *curHandlePtrPtr = (Fsio_FileIOHandle *)NIL;
  1440.         }
  1441.     }
  1442.     }
  1443.     if (status != SUCCESS)  { 
  1444.     free((Address) newDescPtr);
  1445.     } else {
  1446.        (void)Fsdm_FileDescStore(parentHandlePtr, FALSE);
  1447.     }
  1448.     return(status);
  1449. }
  1450.  
  1451.  
  1452. /*
  1453.  *----------------------------------------------------------------------
  1454.  *
  1455.  * WriteNewDirectory --
  1456.  *      Write a new sub-directory.  Set the file numbers on the canned image
  1457.  *      of a new directory and write the block to the directory.
  1458.  *
  1459.  * Results:
  1460.  *    SUCCESS or an error code.
  1461.  *
  1462.  * Side effects:
  1463.  *    Disk I/O to write the directory data block.
  1464.  *
  1465.  *----------------------------------------------------------------------
  1466.  */
  1467. static    ReturnStatus
  1468. WriteNewDirectory(curHandlePtr, parentHandlePtr)
  1469.     Fsio_FileIOHandle *curHandlePtr;        /* Handle of file to delete */
  1470.     Fsio_FileIOHandle *parentHandlePtr;    /* Handle of directory in which
  1471.                          * to delete file*/
  1472. {
  1473.     ReturnStatus    status;
  1474.     int            offset;
  1475.     int            length;
  1476.     register Fslcl_DirEntry *dirEntryPtr;
  1477.     char        *dirBlock;
  1478.  
  1479.     /*
  1480.      * The malloc and Byte_Copy could be avoided by puting this routine
  1481.      * into its own monitor so that it could write directly onto fslclEmptyDirBlock
  1482.      * fslclEmptyDirBlock is already set up with ".", "..", and the correct
  1483.      * nameLengths and recordLengths.
  1484.      */
  1485.     dirBlock = (char *)malloc(FSLCL_DIR_BLOCK_SIZE);
  1486.     bcopy((Address)fslclEmptyDirBlock, (Address)dirBlock, FSLCL_DIR_BLOCK_SIZE);
  1487.     dirEntryPtr = (Fslcl_DirEntry *)dirBlock;
  1488.     dirEntryPtr->fileNumber = curHandlePtr->hdr.fileID.minor;
  1489.     dirEntryPtr = (Fslcl_DirEntry *)((int)dirEntryPtr +
  1490.                  dirEntryPtr->recordLength);
  1491.     dirEntryPtr->fileNumber = parentHandlePtr->hdr.fileID.minor;
  1492.     offset = 0;
  1493.     length = FSLCL_DIR_BLOCK_SIZE;
  1494.     status = Fscache_Write(&curHandlePtr->cacheInfo, 0, (Address)dirBlock,
  1495.         offset, &length, (Sync_RemoteWaiter *)NIL);
  1496.     if (status == SUCCESS) {
  1497.     (void)Fsdm_UpdateDescAttr(curHandlePtr, &curHandlePtr->cacheInfo.attr, 
  1498.             FSDM_FD_MODTIME_DIRTY);
  1499.     }
  1500.     free(dirBlock);
  1501.     return(status);
  1502. }
  1503.  
  1504.  
  1505. /*
  1506.  *----------------------------------------------------------------------
  1507.  *
  1508.  * LinkFile --
  1509.  *    Create an entry in a directory that references an existing file.
  1510.  *    This understands that links to directories are made as part of
  1511.  *    a rename and checks that no circularities in the directory structure
  1512.  *    result from moving a directory.  Other than that it is left to
  1513.  *    the caller to check permissions.
  1514.  *
  1515.  * Results:
  1516.  *    SUCCESS or an error code.
  1517.  *
  1518.  * Side effects:
  1519.  *    Calls InsertComponent, bumps the link count on the existing file.
  1520.  *    Calls MoveDirectory in the case of directories.
  1521.  *
  1522.  *----------------------------------------------------------------------
  1523.  */
  1524. static ReturnStatus
  1525. LinkFile(parentHandlePtr, component, compLen, fileNumber, logOp,curHandlePtrPtr)
  1526.     Fsio_FileIOHandle    *parentHandlePtr;/* Handle of directory in which to add 
  1527.                      * file. */
  1528.     char    *component;        /* Name of the file */
  1529.     int        compLen;        /* The length of component */
  1530.     int        fileNumber;        /* Domain relative file number */
  1531.     int        logOp;
  1532.     Fsio_FileIOHandle    **curHandlePtrPtr;/* Return, handle for the new file */
  1533. {
  1534.     ReturnStatus    status;
  1535.     Fsdm_FileDescriptor    *linkDescPtr;    /* Descriptor for the existing file */
  1536.     Time         modTime;    /* Descriptors are modified */
  1537.     ClientData        logClientData;
  1538.     int            dirOffset;
  1539.  
  1540.     if (fileNumber == parentHandlePtr->hdr.fileID.minor) {
  1541.     /*
  1542.      * Trying to move a directory into itself, ie. % mv subdir subdir
  1543.      */
  1544.     return(GEN_INVALID_ARG);
  1545.     }
  1546.     status = GetHandle(fileNumber, (Fsdm_FileDescriptor *) NIL,
  1547.             parentHandlePtr, component, curHandlePtrPtr);
  1548.     if (status != SUCCESS) {
  1549.     printf( "LinkFile: can't get existing file handle\n");
  1550.     return(FAILURE);
  1551.     } else if ((*curHandlePtrPtr)->descPtr->fileType == FS_DIRECTORY) {
  1552.     logOp |= FSDM_LOG_IS_DIRECTORY;
  1553.     status = OkToMoveDirectory(parentHandlePtr, *curHandlePtrPtr);
  1554.     }
  1555.     if (status == SUCCESS) {
  1556.     linkDescPtr = (*curHandlePtrPtr)->descPtr;
  1557.     logClientData = Fsdm_DirOpStart(logOp, parentHandlePtr, -1,
  1558.                 component, compLen, fileNumber, 
  1559.                     linkDescPtr->fileType,
  1560.                     linkDescPtr);
  1561.     linkDescPtr->numLinks++;
  1562.     linkDescPtr->descModifyTime = Fsutil_TimeInSeconds();
  1563.     linkDescPtr->flags |= FSDM_FD_LINKS_DIRTY;
  1564.     status = Fsdm_FileDescStore(*curHandlePtrPtr, FALSE);
  1565.     if (status == SUCCESS) {
  1566.         /*
  1567.          * Commit by adding the name to the directory.
  1568.          */
  1569.         status = InsertComponent(parentHandlePtr, component, compLen,
  1570.                         fileNumber, &dirOffset);
  1571.         if ((*curHandlePtrPtr)->descPtr->fileType == FS_DIRECTORY &&
  1572.         status == SUCCESS) {
  1573.         /*
  1574.          * This link is part of a rename (links to directories are
  1575.          * only allowed at this time), and the ".." entry in the
  1576.          * directory may have to be fixed.
  1577.          */
  1578.         modTime.seconds = Fsutil_TimeInSeconds();
  1579.         status = MoveDirectory(&modTime, parentHandlePtr,
  1580.                             *curHandlePtrPtr);
  1581.         if (status != SUCCESS) {
  1582.             (void)DeleteComponent(parentHandlePtr, component,
  1583.                             compLen, &dirOffset);
  1584.         }
  1585.         }
  1586.         if (status != SUCCESS) {
  1587.         /*
  1588.          * Couldn't add to the directory because of I/O probably.
  1589.          * Unwind by reducing the link count.  This gets the cache
  1590.          * consistent with the cached directory image anyway.
  1591.          */
  1592.         linkDescPtr->numLinks--;
  1593.         linkDescPtr->flags |= FSDM_FD_LINKS_DIRTY;
  1594.         (void)Fsdm_FileDescStore(*curHandlePtrPtr, FALSE);
  1595.         Fsutil_HandleRelease(*curHandlePtrPtr, TRUE);
  1596.         *curHandlePtrPtr = (Fsio_FileIOHandle *)NIL;
  1597.         } else {
  1598.         (void)Fsdm_FileDescStore(parentHandlePtr, FALSE);
  1599.         }
  1600.     } else {
  1601.         linkDescPtr->numLinks--;
  1602.         linkDescPtr->flags &= ~FSDM_FD_LINKS_DIRTY;
  1603.     }
  1604.     Fsdm_DirOpEnd(logOp, parentHandlePtr, dirOffset, 
  1605.           component, compLen, fileNumber, linkDescPtr->fileType,
  1606.           linkDescPtr, logClientData, status);
  1607.     }
  1608.     return(status);
  1609. }
  1610.  
  1611.  
  1612. /*
  1613.  *----------------------------------------------------------------------
  1614.  *
  1615.  * OkToMoveDirectory --
  1616.  *
  1617.  *    Check that it is ok to move a directory.  Dis-connected trees and
  1618.  *    loops in directory structure are prevented here.
  1619.  *
  1620.  * Results:
  1621.  *    A return code.
  1622.  *
  1623.  * Side effects:
  1624.  *    File handles are momentarily locked on the route from the new
  1625.  *    position in the hierarchy up to the root to check against illegal moves.
  1626.  *    This action might cause deadlock with another process desending along
  1627.  *    same route, descenders hold a lock on the parent while they try for
  1628.  *    a lock on the next sub-directory.
  1629.  *
  1630.  *----------------------------------------------------------------------
  1631.  */
  1632. static ReturnStatus
  1633. OkToMoveDirectory(newParentHandlePtr, curHandlePtr)
  1634.     Fsio_FileIOHandle *newParentHandlePtr;    /* New parent directory for
  1635.                          * curHandlePtr */
  1636.     Fsio_FileIOHandle *curHandlePtr;        /* Directory being moved */
  1637. {
  1638.     ReturnStatus    status;
  1639.     int         oldParentFileNumber;    /* File number of original 
  1640.                          * parent directory. */
  1641.     int            newParentNumber;    /* File number of new 
  1642.                          * parent directory. */
  1643.  
  1644.     status = GetParentNumber(curHandlePtr, &oldParentFileNumber);
  1645.     if (status != SUCCESS) {
  1646.     return(status);
  1647.     }
  1648.     newParentNumber = newParentHandlePtr->hdr.fileID.minor;
  1649.     if (oldParentFileNumber == newParentNumber) {
  1650.     /*
  1651.      * ".." entry is ok because the rename is within the same directory.
  1652.      */
  1653.     status = SUCCESS;
  1654.     } else {
  1655.     /*
  1656.      * Have to trace up from the new parent to make sure we don't find
  1657.      * the current file.  If we let that happen then you create
  1658.      * dis-connected loops in the directory structure.
  1659.      */
  1660.     Fsio_FileIOHandle *parentHandlePtr;
  1661.     int parentNumber;
  1662.  
  1663.     for (parentNumber = newParentNumber; status == SUCCESS; ) {
  1664.         if (parentNumber == curHandlePtr->hdr.fileID.minor) {
  1665.         status = FS_INVALID_ARG;
  1666.         } else if (parentNumber == FSDM_ROOT_FILE_NUMBER ||
  1667.                parentNumber == oldParentFileNumber) {
  1668.         break;
  1669.         } else {
  1670.         /*
  1671.          * Advance parentNumber upwards towards the root.  The
  1672.          * handles are locked because of the I/O required to get
  1673.          * the parent file number.  We have to be careful when
  1674.          * locking the parents because the first parent
  1675.          * (newParentHandlePtr) is already locked by us.
  1676.          *
  1677.          * It still seems like there is a possibility of deadlock if
  1678.          * someone is desending into newParentHandlePtr and has a lock
  1679.          * on the directory above that.  FIX ME
  1680.          */
  1681.         if (parentNumber != newParentNumber) {
  1682.             status = GetHandle(parentNumber,
  1683.                (Fsdm_FileDescriptor *) NIL,   curHandlePtr, (char *)NIL,
  1684.                     &parentHandlePtr);
  1685.         } else {
  1686.             parentHandlePtr = newParentHandlePtr;
  1687.         }
  1688.         if (status == SUCCESS) {
  1689.             status = GetParentNumber(parentHandlePtr, &parentNumber);
  1690.         }
  1691.         if (parentHandlePtr != newParentHandlePtr) {
  1692.             (void)Fsutil_HandleRelease(parentHandlePtr, TRUE);
  1693.         }
  1694.         }
  1695.     }
  1696.     }
  1697.     return(status);
  1698. }
  1699.  
  1700.  
  1701. /*
  1702.  *----------------------------------------------------------------------
  1703.  *
  1704.  * MoveDirectory --
  1705.  *
  1706.  *    Complete the moving of a directory by updating its reference to
  1707.  *    its parent and incrementing the link count on its new parent.
  1708.  *
  1709.  * Results:
  1710.  *    A return code.
  1711.  *
  1712.  * Side effects:
  1713.  *    Sets the directory's parent entry to reference the parent passed in.
  1714.  *    Increments the link count on the new parent.
  1715.  *
  1716.  *----------------------------------------------------------------------
  1717.  */
  1718. static ReturnStatus
  1719. MoveDirectory( modTimePtr, newParentHandlePtr, curHandlePtr)
  1720.     Time    *modTimePtr;            /* Modify time for parent */
  1721.     Fsio_FileIOHandle    *newParentHandlePtr;    /* New parent directory for 
  1722.                          * curHandlePtr */
  1723.     Fsio_FileIOHandle    *curHandlePtr;        /* Directory being moved */
  1724. {
  1725.     ReturnStatus    status;
  1726.     int            oldParentFileNumber;    /* File number of original 
  1727.                          * parent directory */
  1728.     int            newParentNumber;    /* File number of new 
  1729.                          * parent directory */
  1730.  
  1731.     status = GetParentNumber(curHandlePtr, &oldParentFileNumber);
  1732.     if (status != SUCCESS) {
  1733.     printf(
  1734.           "MoveDirectory: Can't get parent's file number\n");
  1735.     } else {
  1736.     newParentNumber = newParentHandlePtr->hdr.fileID.minor;
  1737.     if (oldParentFileNumber != newParentNumber) {
  1738.         /*
  1739.          * Patch the directory entry for ".."
  1740.          */
  1741.         FSLCL_HASH_DELETE(fslclNameTablePtr, "..", curHandlePtr);
  1742.         status = SetParentNumber(curHandlePtr, newParentNumber);
  1743.     }
  1744.     if (status == SUCCESS) {
  1745.         /*
  1746.          * Increment the link count on the new parent.  The old parent's
  1747.          * link count gets decremented when the orignial instance of the
  1748.          * directory is removed.  This is done even if the move is within
  1749.          * the same directory because deleting the original name later will
  1750.          * reduce the link count.
  1751.          */
  1752.         register Fsdm_FileDescriptor *parentDescPtr;
  1753.  
  1754.         parentDescPtr = newParentHandlePtr->descPtr;
  1755.         parentDescPtr->numLinks++;
  1756.         parentDescPtr->descModifyTime = modTimePtr->seconds;
  1757.         parentDescPtr->flags |= FSDM_FD_LINKS_DIRTY;
  1758.         (void)Fsdm_FileDescStore(newParentHandlePtr, FALSE);
  1759.     }
  1760.     }
  1761.     return(status);
  1762. }
  1763.  
  1764.  
  1765. /*
  1766.  *----------------------------------------------------------------------
  1767.  *
  1768.  * GetParentNumber --
  1769.  *    Read a directory to determine the file number of the parent.
  1770.  *
  1771.  * Results:
  1772.  *    SUCCESS or an error code, sets *parentNumberPtr to be the file number
  1773.  *    from the ".." entry in the directory.
  1774.  *
  1775.  * Side effects:
  1776.  *    None, except for the I/O to read the directory block.
  1777.  *
  1778.  *----------------------------------------------------------------------
  1779.  */
  1780. static ReturnStatus
  1781. GetParentNumber(curHandlePtr, parentNumberPtr)
  1782.     Fsio_FileIOHandle    *curHandlePtr;    /* Handle for current directory */
  1783.     int        *parentNumberPtr;    /* Result, the file number of the parent
  1784.                      * of curHandlePtr */
  1785. {
  1786.     ReturnStatus     status;
  1787.     int         length;
  1788.     register Fslcl_DirEntry *dirEntryPtr;
  1789.     Fscache_Block    *cacheBlockPtr;
  1790.  
  1791.     status = Fscache_BlockRead(&curHandlePtr->cacheInfo, 0, &cacheBlockPtr,
  1792.                 &length, FSCACHE_DIR_BLOCK, FALSE);
  1793.     if (status != SUCCESS) {
  1794.     return(status);
  1795.     } else if (length == 0) {
  1796.     return(FAILURE);
  1797.     }
  1798.  
  1799.     dirEntryPtr = (Fslcl_DirEntry *)cacheBlockPtr->blockAddr;
  1800.     if (dirEntryPtr->nameLength != 1 ||
  1801.     dirEntryPtr->fileName[0] != '.' ||
  1802.     dirEntryPtr->fileName[1] != '\0') {
  1803.     printf(
  1804.           "GetParentNumber: \".\", corrupted directory\n");
  1805.     status = FAILURE;
  1806.     } else {
  1807.     dirEntryPtr = 
  1808.         (Fslcl_DirEntry *)((int)dirEntryPtr + dirEntryPtr->recordLength);
  1809.     if (dirEntryPtr->nameLength != 2 ||
  1810.         dirEntryPtr->fileName[0] != '.' ||
  1811.         dirEntryPtr->fileName[1] != '.' ||
  1812.         dirEntryPtr->fileName[2] != '\0') {
  1813.         printf(
  1814.               "GetParentNumber: \"..\", corrupted directory\n");
  1815.         status = FAILURE;
  1816.     } else {
  1817.         *parentNumberPtr = dirEntryPtr->fileNumber;
  1818.     }
  1819.     }
  1820.     Fscache_UnlockBlock(cacheBlockPtr, 0, -1, 0, FSCACHE_CLEAR_READ_AHEAD);
  1821.  
  1822.     return(status);
  1823. }
  1824.  
  1825.  
  1826. /*
  1827.  *----------------------------------------------------------------------
  1828.  *
  1829.  * SetParentNumber --
  1830.  *    Patch the file number for the ".." entry of a directory.
  1831.  *
  1832.  * Results:
  1833.  *    SUCCESS or an error code from the I/O.
  1834.  *
  1835.  * Side effects:
  1836.  *    Changes the parent file number of the ".." entry.
  1837.  *
  1838.  *----------------------------------------------------------------------
  1839.  */
  1840. static ReturnStatus
  1841. SetParentNumber(curHandlePtr, newParentNumber)
  1842.     Fsio_FileIOHandle    *curHandlePtr;    /* Handle for current directory */
  1843.     int         newParentNumber;/* The new file number of the parent
  1844.                      * of curHandlePtr */
  1845. {
  1846.     ReturnStatus    status;
  1847.     int         length;
  1848.     register Fslcl_DirEntry *dirEntryPtr;
  1849.     Fscache_Block    *cacheBlockPtr;
  1850.  
  1851.     status = Fscache_BlockRead(&curHandlePtr->cacheInfo, 0, &cacheBlockPtr,
  1852.                 &length, FSCACHE_DIR_BLOCK, FALSE);
  1853.     if (status != SUCCESS) {
  1854.     return(status);
  1855.     } else if (length == 0) {
  1856.     return(FAILURE);
  1857.     }
  1858.     dirEntryPtr = (Fslcl_DirEntry *)cacheBlockPtr->blockAddr;
  1859.     if (dirEntryPtr->nameLength != 1 ||
  1860.     dirEntryPtr->fileName[0] != '.' ||
  1861.     dirEntryPtr->fileName[1] != '\0') {
  1862.     printf(
  1863.           "SetParentNumber: \".\", corrupted directory\n");
  1864.     Fscache_UnlockBlock(cacheBlockPtr, 0, -1, 0, FSCACHE_CLEAR_READ_AHEAD);
  1865.     return(FAILURE);
  1866.     }
  1867.     dirEntryPtr = (Fslcl_DirEntry *)((int)dirEntryPtr + dirEntryPtr->recordLength);
  1868.     if (dirEntryPtr->nameLength != 2 ||
  1869.     dirEntryPtr->fileName[0] != '.' ||
  1870.     dirEntryPtr->fileName[1] != '.' ||
  1871.     dirEntryPtr->fileName[2] != '\0') {
  1872.     printf("SetParentNumber: \"..\", corrupted directory\n");
  1873.     Fscache_UnlockBlock(cacheBlockPtr, 0, -1, 0, FSCACHE_CLEAR_READ_AHEAD);
  1874.     return(FAILURE);
  1875.     }
  1876.     dirEntryPtr->fileNumber = newParentNumber;
  1877.     status = CacheDirBlockWrite(curHandlePtr, cacheBlockPtr, 0, length);
  1878.     return(status);
  1879. }
  1880.  
  1881.  
  1882. /*
  1883.  *----------------------------------------------------------------------
  1884.  *
  1885.  * DeleteFileName --
  1886.  *
  1887.  *      Delete a file by clearing its fileNumber in the directory and
  1888.  *    reducing its link count.  
  1889.  *
  1890.  * Results:
  1891.  *    SUCCESS or an error code.
  1892.  *
  1893.  * Side effects:
  1894.  *    Log entry may be written.
  1895.  *
  1896.  *----------------------------------------------------------------------
  1897.  */
  1898. static ReturnStatus
  1899. DeleteFileName(parentHandlePtr, curHandlePtr, component,
  1900.          compLen, forRename, idPtr, logOp)
  1901.     Fsio_FileIOHandle *parentHandlePtr;    /* Handle of directory in
  1902.                          * which to delete file*/
  1903.     Fsio_FileIOHandle *curHandlePtr;    /* Handle of file to delete */
  1904.     char *component;                /* Name of the file to delte */
  1905.     int compLen;                /* The length of component */
  1906.     int forRename;        /* if FS_RENAME, then the file being delted
  1907.                  * is being renamed.  This allows non-empty
  1908.                  * directories to be deleted */
  1909.     Fs_UserIDs *idPtr;        /* User and group IDs */
  1910.     int        logOp;        /* Directory log operation.; */
  1911. {
  1912.     ReturnStatus status;
  1913.     Fsdm_FileDescriptor *parentDescPtr;    /* Descriptor for parent */
  1914.     Fsdm_FileDescriptor *curDescPtr;    /* Descriptor for the file to delete */
  1915.     int type;                /* Type of the file */
  1916.     int    fileNumber;            /* Number of file being deleted. */
  1917.     ClientData    logClientData;        /* ClientData returned from 
  1918.                      * DirOpStart. */
  1919.     int dirOffset;
  1920.  
  1921.     type = curHandlePtr->descPtr->fileType;
  1922.     if (parentHandlePtr == (Fsio_FileIOHandle *)NIL) {
  1923.     /*
  1924.      * There is no handle on the parent because we have just
  1925.      * gone up via "..".  You can't delete the parent.
  1926.      */
  1927.     status = FS_NO_ACCESS;
  1928.     } else if ((compLen == 1) && (component[0] == '.')) {
  1929.     /*
  1930.      * Disallow removing dot.
  1931.      */
  1932.     status = FS_NO_ACCESS;
  1933.     } else if (type == FS_DIRECTORY && (!forRename) &&
  1934.         !DirectoryEmpty(curHandlePtr)) {
  1935.     status = FS_DIR_NOT_EMPTY;
  1936.     } else {
  1937.     /*
  1938.      * One needs write permission in the parent to do the delete.
  1939.      */
  1940.     status = CheckPermissions(parentHandlePtr, FS_WRITE, idPtr,
  1941.                     FS_DIRECTORY);
  1942.     }
  1943.     if (status != SUCCESS) {
  1944.     return(status);
  1945.     }
  1946.     curDescPtr = curHandlePtr->descPtr;
  1947.     parentDescPtr = parentHandlePtr->descPtr;
  1948.     fileNumber = curHandlePtr->hdr.fileID.minor;
  1949.     dirOffset = -1;
  1950.  
  1951.     if (type == FS_DIRECTORY) {
  1952.     logOp |= FSDM_LOG_IS_DIRECTORY;
  1953.     }
  1954.     logClientData = Fsdm_DirOpStart(logOp, parentHandlePtr, dirOffset, 
  1955.             component, compLen, fileNumber, type,
  1956.             curHandlePtr->descPtr);
  1957.     /*
  1958.      * Remove the name from the directory first.
  1959.      */
  1960.     status = DeleteComponent(parentHandlePtr, component, compLen, &dirOffset);
  1961.     if (status == SUCCESS) {
  1962.     curDescPtr->numLinks--;
  1963.     curDescPtr->flags |= FSDM_FD_LINKS_DIRTY;
  1964.     if (type == FS_DIRECTORY) {
  1965.         /*
  1966.          * The directory might have been known in the hash table as
  1967.          * someone's "..". Besure that this entry is gone.
  1968.          */
  1969.         FSLCL_HASH_DELETE(fslclNameTablePtr, "..", curHandlePtr);
  1970.         if (!forRename) {
  1971.         /*
  1972.          * Directories have an extra link because they reference 
  1973.          * themselves.
  1974.          */
  1975.         curDescPtr->numLinks--;
  1976.         if (curDescPtr->numLinks > 0) {
  1977.             printf("DeleteFileName: extra links on directory\n");
  1978.         }
  1979.         }
  1980.     }
  1981.     curDescPtr->descModifyTime = Fsutil_TimeInSeconds();
  1982.     status = Fsdm_FileDescStore(curHandlePtr, FALSE);
  1983.     if (status != SUCCESS) {
  1984.         printf("DeleteFileName: (1) Couldn't store descriptor\n");
  1985. #ifdef notdef
  1986.         return(status);
  1987. #endif
  1988.     }
  1989.     if (type == FS_DIRECTORY) {
  1990.         /*
  1991.          * A directory's link count reflects the number of subdirectories
  1992.          * it has (they each have a ".." that references it.)  Here
  1993.          * it is decremented because the subdirectory is going away.
  1994.          */
  1995.         parentDescPtr->numLinks--;
  1996.         parentDescPtr->descModifyTime = Fsutil_TimeInSeconds();
  1997.         parentDescPtr->flags |= FSDM_FD_LINKS_DIRTY;
  1998.     }
  1999.     status = Fsdm_FileDescStore(parentHandlePtr, FALSE);
  2000.     if (status != SUCCESS) {
  2001.         printf("DeleteFileName: (2) Couldn't store descriptor\n");
  2002. #ifdef notdef
  2003.         return(status);
  2004. #endif
  2005.     }
  2006.     if ((curDescPtr->numLinks <= 0) && (curHandlePtr->use.ref != 0)) {
  2007.         logOp |= FSDM_LOG_STILL_OPEN;
  2008.     }
  2009.     } 
  2010.     Fsdm_DirOpEnd(logOp, parentHandlePtr, dirOffset,
  2011.                 component, compLen, fileNumber, type,
  2012.             curDescPtr, logClientData, status);
  2013.     return(status);
  2014. }
  2015.  
  2016. /*
  2017.  *----------------------------------------------------------------------
  2018.  *
  2019.  * CloseDeletedFile --
  2020.  *
  2021.  *    This routine is called to close a deleted file.
  2022.  *    If there are no links left then the
  2023.  *    file's handle is marked as deleted.  Finally, if this routine
  2024.  *    has the last reference on the handle then the file's data blocks
  2025.  *    are truncated away and the file descriptor is marked as free.
  2026.  *
  2027.  *    This is a separate routine from DeleteFileName because the
  2028.  *    file cannot be closed unless the parent handle is unlocked
  2029.  *    (to prevent deadlock while doing the consistency callback),
  2030.  *    and the code to do a rename deletes the existing file, then
  2031.  *    does a link.  This would break if the parent handle was
  2032.  *    released during the delete.
  2033.  *
  2034.  * Results:
  2035.  *    SUCCESS or error code.
  2036.  *
  2037.  * Side effects:
  2038.  *    The parent and/or current handles may be released and set to NIL.
  2039.  *
  2040.  *----------------------------------------------------------------------
  2041.  */
  2042.  
  2043. static void
  2044. CloseDeletedFile(parentHandlePtrPtr, curHandlePtrPtr)
  2045.     Fsio_FileIOHandle **parentHandlePtrPtr;    /* Handle of parent of
  2046.                          * deleted file. */
  2047.     Fsio_FileIOHandle **curHandlePtrPtr;    /* Handle of deleted file. */
  2048.  
  2049. {
  2050.     register Fsio_FileIOHandle *curHandlePtr;    /* Local copy */
  2051.  
  2052.     curHandlePtr = *curHandlePtrPtr;
  2053.     if (curHandlePtr->descPtr->numLinks <= 0) {
  2054.     /*
  2055.      * At this point curHandlePtr is potentially the last reference
  2056.      * to the file.  If there are no users then do the delete, otherwise
  2057.      * mark the handle as deleted and Fsio_FileClose will take care of 
  2058.      * it.
  2059.      */
  2060.     curHandlePtr->flags |= FSIO_FILE_NAME_DELETED;
  2061.     if (curHandlePtr->use.ref == 0) {
  2062.         /*
  2063.          * Handle the deletion and clean up the handle.
  2064.          * We set the the clientID to us and specify client
  2065.          * call-backs so that any other clients will be notified.
  2066.          */
  2067.         Fsutil_HandleRelease(*parentHandlePtrPtr, TRUE);
  2068.         *parentHandlePtrPtr = (Fsio_FileIOHandle *)NIL;
  2069.         (void)Fsio_FileCloseInt(curHandlePtr, 0, 0, 0, rpc_SpriteID, 
  2070.             TRUE);
  2071.         *curHandlePtrPtr = (Fsio_FileIOHandle *)NIL;
  2072.     } else {
  2073.         Fsutil_HandleRelease(curHandlePtr, TRUE);
  2074.         *curHandlePtrPtr = (Fsio_FileIOHandle *)NIL;
  2075.     }
  2076.     } else {
  2077.     Fsutil_HandleRelease(curHandlePtr, TRUE);
  2078.     *curHandlePtrPtr = (Fsio_FileIOHandle *)NIL;
  2079.     }
  2080. }
  2081.  
  2082.  
  2083. /*
  2084.  *----------------------------------------------------------------------
  2085.  *
  2086.  * Fslcl_DeleteFileDesc --
  2087.  *    Delete a file from disk given its file handle.  It is assumed that the
  2088.  *    file's name has already been deleted from the directory structure.
  2089.  *
  2090.  * Results:
  2091.  *    None.
  2092.  *
  2093.  * Side effects:
  2094.  *    Delete the data blocks and mark file descriptor as free.  The
  2095.  *    handle remains locked during this call.  The DESCRIPTOR referenced
  2096.  *    by the handle is FREED because the file handle is going to
  2097.  *    be removed.
  2098.  *
  2099.  *----------------------------------------------------------------------
  2100.  */
  2101.  
  2102. ReturnStatus
  2103. Fslcl_DeleteFileDesc(handlePtr)
  2104.     Fsio_FileIOHandle *handlePtr;
  2105. {
  2106.     ReturnStatus status;
  2107.     Fsdm_Domain *domainPtr;
  2108.  
  2109.     if (handlePtr->descPtr->fileType == FS_DIRECTORY) {
  2110.     /*
  2111.      * Remove .. from the name cache so we don't end up with
  2112.      * a bad cache entry later when this directory is re-created.
  2113.      */
  2114.     FSLCL_HASH_DELETE(fslclNameTablePtr, "..", handlePtr);
  2115.     }
  2116.  
  2117.     domainPtr = Fsdm_DomainFetch(handlePtr->hdr.fileID.major, FALSE);
  2118.     if (domainPtr == (Fsdm_Domain *)NIL) {
  2119.     return(FS_DOMAIN_UNAVAILABLE);
  2120.     }
  2121.     /*
  2122.      * The ordering of the deletion is as follows:
  2123.      * 1. Mark the descriptor on disk as free so if we crash the
  2124.      *        disk scavenger will free the blocks for us.
  2125.      * 2. Truncate the blocks out of the cache and from the descriptor.
  2126.      * 3. Mark the file descriptor as available in the bitmask.
  2127.      */
  2128.     FSUTIL_TRACE_HANDLE(FSUTIL_TRACE_DELETE, ((Fs_HandleHeader *)handlePtr));
  2129.     handlePtr->descPtr->flags = FSDM_FD_FREE | FSDM_FD_DIRTY;
  2130.     status = Fsdm_FileDescStore(handlePtr,TRUE);
  2131.     if (status != SUCCESS) {
  2132.     printf("Fslcl_DeleteFileDesc: Can't mark descriptor as free\n");
  2133.     } else {
  2134.     status = Fsio_FileTrunc(handlePtr, 0, FSCACHE_TRUNC_DELETE);
  2135.     if (status != SUCCESS) {
  2136.         printf("Fslcl_DeleteFileDesc: Can't truncate file <%d,%d> \"%s\"\n",
  2137.             handlePtr->hdr.fileID.major, handlePtr->hdr.fileID.minor,
  2138.             Fsutil_HandleName(handlePtr));
  2139.     } else {
  2140.         (void)Fsdm_FreeFileNumber(domainPtr, handlePtr->hdr.fileID.minor);
  2141.     }
  2142.     free((Address)handlePtr->descPtr);
  2143.     handlePtr->descPtr = (Fsdm_FileDescriptor *)NIL;
  2144.     }
  2145.     Fsdm_DomainRelease(handlePtr->hdr.fileID.major);
  2146.     return(status);
  2147. }
  2148.  
  2149. /*
  2150.  *----------------------------------------------------------------------
  2151.  *
  2152.  * DirectoryEmpty --
  2153.  *    Scan a directory and determine if there are any files left
  2154.  *    in it other than "." and "..".
  2155.  *
  2156.  * Results:
  2157.  *    TRUE if the directory is empty, FALSE otherwise.
  2158.  *
  2159.  * Side effects:
  2160.  *    None.
  2161.  *
  2162.  *----------------------------------------------------------------------
  2163.  */
  2164.  
  2165. static Boolean
  2166. DirectoryEmpty(handlePtr)
  2167.     Fsio_FileIOHandle *handlePtr;    /* Handle of directory to check */
  2168. {
  2169.     ReturnStatus    status;
  2170.     int         blockOffset;    /* Offset within a directory block */
  2171.     Fslcl_DirEntry         *dirEntryPtr;    /* Reference to directory entry */
  2172.     int         length;        /* Length for read call */
  2173.     int            dirBlockNum;
  2174.     Fscache_Block    *cacheBlockPtr;
  2175.  
  2176.     dirBlockNum = 0;
  2177.     do {
  2178.     status = Fscache_BlockRead(&handlePtr->cacheInfo, dirBlockNum,
  2179.               &cacheBlockPtr, &length, FSCACHE_DIR_BLOCK, FALSE);
  2180.     if (status != SUCCESS || length == 0) {
  2181.         /*
  2182.          * Have run out of the directory and not found anything.
  2183.          */
  2184.         return(TRUE);
  2185.     }
  2186.     blockOffset = 0;
  2187.     dirEntryPtr = (Fslcl_DirEntry *)cacheBlockPtr->blockAddr;
  2188.     while (blockOffset < length) {
  2189.         if (dirEntryPtr->fileNumber != 0) {
  2190.         /*
  2191.          * A valid directory record.
  2192.          */
  2193.         if ((strcmp(".", dirEntryPtr->fileName) == 0) ||
  2194.             (strcmp("..", dirEntryPtr->fileName) == 0)) {
  2195.             /*
  2196.              * "." and ".." are ok
  2197.              */
  2198.         } else {
  2199.             Fscache_UnlockBlock(cacheBlockPtr, 0, -1, 0, 
  2200.                     FSCACHE_CLEAR_READ_AHEAD);
  2201.             return(FALSE);
  2202.         }
  2203.         }
  2204.         blockOffset += dirEntryPtr->recordLength;
  2205.         dirEntryPtr = 
  2206.         (Fslcl_DirEntry *)((int)dirEntryPtr + dirEntryPtr->recordLength);
  2207.     }
  2208.     dirBlockNum++;
  2209.     Fscache_UnlockBlock(cacheBlockPtr, 0, -1, 0, FSCACHE_CLEAR_READ_AHEAD);
  2210.     } while(TRUE);
  2211.     /*NOTREACHED*/
  2212. }
  2213.  
  2214. /*
  2215.  *----------------------------------------------------------------------
  2216.  *
  2217.  * CheckPermissions --
  2218.  *
  2219.  *    Check permissions on a file during lookup.  This just looks
  2220.  *    at the uid, groupIDs, and the permission bits on the file.
  2221.  *    
  2222.  *    Some semantic checking is done:
  2223.  *        type indicates what kind of file to accept.
  2224.  *        Execution of files with no execute bit is prevented for uid = 0
  2225.  *        Execution of directories is prevented.
  2226.  *    Some semantic checking is not done:
  2227.  *        Doesn't check against writing to directories.  This is
  2228.  *        done later in the FileSrvOpen routine.
  2229.  *
  2230.  * Results:
  2231.  *    FS_NO_ACCESS if the useFlags include a permission that does
  2232.  *    not fit with the uid/groupIDs of the file.
  2233.  *
  2234.  * Side effects:
  2235.  *    None.
  2236.  *
  2237.  *----------------------------------------------------------------------
  2238.  */
  2239. static ReturnStatus
  2240. CheckPermissions(handlePtr, useFlags, idPtr, type)
  2241.     Fsio_FileIOHandle        *handlePtr;
  2242.     register int        useFlags;
  2243.     register Fs_UserIDs        *idPtr;
  2244.     int             type;
  2245. {
  2246.     register Fsdm_FileDescriptor    *descPtr;
  2247.     register int        *groupPtr;
  2248.     register unsigned int     permBits;
  2249.     register int         index;
  2250.     register int        uid = idPtr->user;
  2251.     ReturnStatus         status;
  2252.  
  2253.     if (handlePtr->hdr.fileID.type != FSIO_LCL_FILE_STREAM) {
  2254.     panic( "CheckPermissions on non-local file\n");
  2255.     return(FAILURE);
  2256.     }
  2257.     descPtr = handlePtr->descPtr;
  2258.     /*
  2259.      * Make sure the file type matches.  FS_FILE means any type, otherwise
  2260.      * it should match exactly.
  2261.      */
  2262.     if (type != FS_FILE && type != descPtr->fileType) {
  2263.     /*
  2264.      * Patch around the fact that FS_REMOTE_LINK and FS_SYMBOLIC_LINK
  2265.      * get or'ed together, but they are not-proper bit fields.
  2266.      * (They equal 3 and 2, respectively.)
  2267.      * Hence we allow a regular symbolic link to satisfy a
  2268.      * request for a remote link.
  2269.      */
  2270.     if ((type == (FS_REMOTE_LINK|FS_SYMBOLIC_LINK)) &&
  2271.         ((descPtr->fileType == FS_SYMBOLIC_LINK) ||
  2272.          (descPtr->fileType == FS_REMOTE_LINK))) {
  2273. /*        printf( "Allowing a symlink for a remote link\n");*/
  2274.     } else {
  2275.         switch(type) {
  2276.         case FS_DIRECTORY:
  2277.             return(FS_NOT_DIRECTORY);
  2278.         default:
  2279.             return(FS_WRONG_TYPE);
  2280.         }
  2281.     }
  2282.     }
  2283.     /*
  2284.      * Dis-allow execution of directories...
  2285.      */
  2286.     if ((type == FS_FILE) && (useFlags & FS_EXECUTE) &&
  2287.     (descPtr->fileType != FS_FILE)) {
  2288.     return(FS_WRONG_TYPE);
  2289.     }
  2290.     /*
  2291.      * Reset SETUID/SETGID bit when writing a file.
  2292.      */
  2293.     if ((useFlags & FS_WRITE) && (descPtr->fileType == FS_FILE) &&
  2294.     (descPtr->permissions & (FS_SET_UID|FS_SET_GID))) {
  2295.     descPtr->permissions &= ~(FS_SET_UID|FS_SET_GID);
  2296.     descPtr->flags |= FSDM_FD_PERMISSIONS_DIRTY;
  2297.     }
  2298.     /*
  2299.      * Check for ownership permission.  This probably redundant with
  2300.      * respect to the checking done by FslclSetAttr.
  2301.      */
  2302. #ifdef notdef
  2303.     if (useFlags & FS_OWNERSHIP) {
  2304.     if ((uid != descPtr->uid) && (uid != 0)) {
  2305.         return(FS_NOT_OWNER);
  2306.     }
  2307.     }
  2308. #endif notdef
  2309.     /*
  2310.      * Check read/write/exec permissions against one of the owner bits,
  2311.      * the group bits, or the world bits.  'permBits' is set to
  2312.      * be the corresponding bits from the file descriptor and then
  2313.      * shifted over so the comparisions are against the WORLD bits.
  2314.      */
  2315.     if (uid == 0) {
  2316.     /*
  2317.      * For normal files, only check for execute permission.  This
  2318.      * prevents root from being able to execute ordinary files by
  2319.      * accident.  However, root has complete access to directories.
  2320.      */
  2321.     if (descPtr->fileType == FS_DIRECTORY) {
  2322.         return(SUCCESS);
  2323.     }
  2324.     useFlags &= FS_EXECUTE;
  2325.     }
  2326.     if (uid == descPtr->uid) {
  2327.     permBits = (descPtr->permissions >> 6) & 07;
  2328.     } else {
  2329.     for (index = idPtr->numGroupIDs, groupPtr = idPtr->group;
  2330.          index > 0;
  2331.          index--, groupPtr++) {
  2332.         if (*groupPtr == descPtr->gid) {
  2333.         permBits = (descPtr->permissions >> 3) & 07;
  2334.         goto havePermBits;
  2335.         }
  2336.     }
  2337.     permBits = descPtr->permissions & 07;
  2338.     }
  2339. havePermBits:
  2340.     if (((useFlags & FS_READ) && ((permBits & FS_WORLD_READ) == 0)) ||
  2341.     ((useFlags & FS_WRITE) && ((permBits & FS_WORLD_WRITE) == 0)) ||
  2342.     ((useFlags & FS_EXECUTE) && ((permBits & FS_WORLD_EXEC) == 0))) {
  2343.     /*
  2344.      * The file's permission don't include what is needed.
  2345.      */
  2346.     status = FS_NO_ACCESS;
  2347.     } else {
  2348.     status = SUCCESS;
  2349.     }
  2350.     return(status);
  2351. }
  2352.  
  2353.  
  2354. /*
  2355.  *----------------------------------------------------------------------
  2356.  *
  2357.  * CacheDirBlockWrite --
  2358.  *
  2359.  *    Write into a cache block returned from Fscache_BlockRead.  Used only
  2360.  *    for writing directories.
  2361.  *
  2362.  * Results:
  2363.  *    SUCCESS unless error when allocating disk space.
  2364.  *
  2365.  * Side effects:
  2366.  *    The cache block is unlocked.  It is deleted if the offset is the
  2367.  *    beginning of the block and the disk allocation failed.
  2368.  *
  2369.  *----------------------------------------------------------------------
  2370.  */
  2371.  
  2372. static ReturnStatus
  2373. CacheDirBlockWrite(handlePtr, blockPtr, blockNum, length)
  2374.     register    Fsio_FileIOHandle    *handlePtr;    /* Handle for file. */
  2375.     register    Fscache_Block    *blockPtr;    /* Cache block. */
  2376.     int                blockNum;    /* Block number. */
  2377.     int                length;        /* Number of valid bytes in
  2378.                          * the block. */
  2379. {
  2380.     ReturnStatus    status = SUCCESS;
  2381.     int            blockAddr = FSDM_NIL_INDEX;
  2382.     Boolean        newBlock;
  2383.     int            flags = FSCACHE_CLEAR_READ_AHEAD;
  2384.     int            offset;
  2385.     int            newLastByte;
  2386.     int            blockSize;
  2387. #ifdef SOSP91
  2388.     Boolean        isForeign = FALSE;    /* Due to migration? */
  2389. #endif SOSP91
  2390.  
  2391. #ifdef SOSP91
  2392.     if (proc_RunningProcesses[0] != (Proc_ControlBlock *) NIL) {
  2393.     if ((proc_RunningProcesses[0]->state == PROC_MIGRATED) ||
  2394.         (proc_RunningProcesses[0]->genFlags &
  2395.         (PROC_FOREIGN | PROC_MIGRATING))) {
  2396.         isForeign = TRUE;
  2397.     }
  2398.     }
  2399. #endif SOSP91
  2400.     offset =  blockNum * FS_BLOCK_SIZE;
  2401.     newLastByte = offset + length - 1;
  2402.     (void) (handlePtr->cacheInfo.backendPtr->ioProcs.allocate)
  2403.     ((Fs_HandleHeader *)handlePtr, offset, length, 0,
  2404.         &blockAddr, &newBlock);
  2405. #ifdef lint
  2406.     (void) Fsdm_BlockAllocate((Fs_HandleHeader *)handlePtr, offset, length,
  2407.             0, &blockAddr, &newBlock);
  2408.     (void) FsrmtBlockAllocate((Fs_HandleHeader *)handlePtr, offset, length,
  2409.             0, &blockAddr, &newBlock);
  2410. #endif /* lint */
  2411.     if (blockAddr == FSDM_NIL_INDEX) {
  2412.     status = FS_NO_DISK_SPACE;
  2413.     if (handlePtr->descPtr->lastByte + 1 < offset) {
  2414.         /*
  2415.          * Delete the block if are appending and this was a new cache
  2416.          * block.
  2417.          */
  2418.         flags = FSCACHE_DELETE_BLOCK;
  2419.     }
  2420.     }
  2421.     Fscache_UpdateDirSize(&handlePtr->cacheInfo, newLastByte);
  2422.     handlePtr->descPtr->dataModifyTime = Fsutil_TimeInSeconds();
  2423.     handlePtr->descPtr->descModifyTime = handlePtr->descPtr->dataModifyTime;
  2424.     handlePtr->descPtr->flags |= FSDM_FD_MODTIME_DIRTY;
  2425.     fs_Stats.blockCache.dirBytesWritten += FSLCL_DIR_BLOCK_SIZE;
  2426.     fs_Stats.blockCache.dirBlockWrites++;
  2427. #ifdef SOSP91
  2428.     if (isForeign) {
  2429.         fs_SospMigStats.blockCache.dirBytesWritten += FSLCL_DIR_BLOCK_SIZE;
  2430.         fs_SospMigStats.blockCache.dirBlockWrites++;
  2431.     }
  2432. #endif SOSP91
  2433.     blockSize = handlePtr->descPtr->lastByte + 1 - (blockNum * FS_BLOCK_SIZE);
  2434.     if (blockSize > FS_BLOCK_SIZE) {
  2435.     blockSize = FS_BLOCK_SIZE;
  2436.     }
  2437.     Fscache_UnlockBlock(blockPtr, (unsigned int)Fsutil_TimeInSeconds(), blockAddr,
  2438.             blockSize, flags);
  2439.     return(status);
  2440. }
  2441.